| [ Index ] |
PHP Cross Reference of Joomla 1.5.26 DE |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @version $Id: table.php 14401 2010-01-26 14:10:00Z louis $ 4 * @package Joomla.Framework 5 * @subpackage Table 6 * @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved. 7 * @license GNU/GPL, see LICENSE.php 8 * Joomla! is free software. This version may have been modified pursuant 9 * to the GNU General Public License, and as distributed it includes or 10 * is derivative of works licensed under the GNU General Public License or 11 * other free or open source software licenses. 12 * See COPYRIGHT.php for copyright notices and details. 13 */ 14 15 // Check to ensure this file is within the rest of the framework 16 defined('JPATH_BASE') or die(); 17 18 /** 19 * Abstract Table class 20 * 21 * Parent classes to all tables. 22 * 23 * @abstract 24 * @package Joomla.Framework 25 * @subpackage Table 26 * @since 1.0 27 * @tutorial Joomla.Framework/jtable.cls 28 */ 29 class JTable extends JObject 30 { 31 /** 32 * Name of the table in the db schema relating to child class 33 * 34 * @var string 35 * @access protected 36 */ 37 var $_tbl = ''; 38 39 /** 40 * Name of the primary key field in the table 41 * 42 * @var string 43 * @access protected 44 */ 45 var $_tbl_key = ''; 46 47 /** 48 * Database connector 49 * 50 * @var JDatabase 51 * @access protected 52 */ 53 var $_db = null; 54 55 /** 56 * Object constructor to set table and key field 57 * 58 * Can be overloaded/supplemented by the child class 59 * 60 * @access protected 61 * @param string $table name of the table in the db schema relating to child class 62 * @param string $key name of the primary key field in the table 63 * @param object $db JDatabase object 64 */ 65 function __construct( $table, $key, &$db ) 66 { 67 $this->_tbl = $table; 68 $this->_tbl_key = $key; 69 $this->_db =& $db; 70 } 71 72 /** 73 * Returns a reference to the a Table object, always creating it 74 * 75 * @param type $type The table type to instantiate 76 * @param string $prefix A prefix for the table class name. Optional. 77 * @param array $options Configuration array for model. Optional. 78 * @return database A database object 79 * @since 1.5 80 */ 81 function &getInstance( $type, $prefix = 'JTable', $config = array() ) 82 { 83 $false = false; 84 85 $type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type); 86 $tableClass = $prefix.ucfirst($type); 87 88 if (!class_exists( $tableClass )) 89 { 90 jimport('joomla.filesystem.path'); 91 if($path = JPath::find(JTable::addIncludePath(), strtolower($type).'.php')) 92 { 93 require_once $path; 94 95 if (!class_exists( $tableClass )) 96 { 97 JError::raiseWarning( 0, 'Table class ' . $tableClass . ' not found in file.' ); 98 return $false; 99 } 100 } 101 else 102 { 103 JError::raiseWarning( 0, 'Table ' . $type . ' not supported. File not found.' ); 104 return $false; 105 } 106 } 107 108 //Make sure we are returning a DBO object 109 if (array_key_exists('dbo', $config)) { 110 $db =& $config['dbo']; 111 } else { 112 $db = & JFactory::getDBO(); 113 } 114 115 $instance = new $tableClass($db); 116 //$instance->setDBO($db); 117 118 return $instance; 119 } 120 121 /** 122 * Get the internal database object 123 * 124 * @return object A JDatabase based object 125 */ 126 function &getDBO() 127 { 128 return $this->_db; 129 } 130 131 /** 132 * Set the internal database object 133 * 134 * @param object $db A JDatabase based object 135 * @return void 136 */ 137 function setDBO(&$db) 138 { 139 $this->_db =& $db; 140 } 141 142 /** 143 * Gets the internal table name for the object 144 * 145 * @return string 146 * @since 1.5 147 */ 148 function getTableName() 149 { 150 return $this->_tbl; 151 } 152 153 /** 154 * Gets the internal primary key name 155 * 156 * @return string 157 * @since 1.5 158 */ 159 function getKeyName() 160 { 161 return $this->_tbl_key; 162 } 163 164 /** 165 * Resets the default properties 166 * @return void 167 */ 168 function reset() 169 { 170 $k = $this->_tbl_key; 171 foreach ($this->getProperties() as $name => $value) 172 { 173 if($name != $k) 174 { 175 $this->$name = $value; 176 } 177 } 178 } 179 180 /** 181 * Binds a named array/hash to this object 182 * 183 * Can be overloaded/supplemented by the child class 184 * 185 * @access public 186 * @param $from mixed An associative array or object 187 * @param $ignore mixed An array or space separated list of fields not to bind 188 * @return boolean 189 */ 190 function bind( $from, $ignore=array() ) 191 { 192 $fromArray = is_array( $from ); 193 $fromObject = is_object( $from ); 194 195 if (!$fromArray && !$fromObject) 196 { 197 $this->setError( get_class( $this ).'::bind failed. Invalid from argument' ); 198 return false; 199 } 200 if (!is_array( $ignore )) { 201 $ignore = explode( ' ', $ignore ); 202 } 203 foreach ($this->getProperties() as $k => $v) 204 { 205 // internal attributes of an object are ignored 206 if (!in_array( $k, $ignore )) 207 { 208 if ($fromArray && isset( $from[$k] )) { 209 $this->$k = $from[$k]; 210 } else if ($fromObject && isset( $from->$k )) { 211 $this->$k = $from->$k; 212 } 213 } 214 } 215 return true; 216 } 217 218 /** 219 * Loads a row from the database and binds the fields to the object properties 220 * 221 * @access public 222 * @param mixed Optional primary key. If not specifed, the value of current key is used 223 * @return boolean True if successful 224 */ 225 function load( $oid=null ) 226 { 227 $k = $this->_tbl_key; 228 229 if ($oid !== null) { 230 $this->$k = $oid; 231 } 232 233 $oid = $this->$k; 234 235 if ($oid === null) { 236 return false; 237 } 238 $this->reset(); 239 240 $db =& $this->getDBO(); 241 242 $query = 'SELECT *' 243 . ' FROM '.$this->_tbl 244 . ' WHERE '.$this->_tbl_key.' = '.$db->Quote($oid); 245 $db->setQuery( $query ); 246 247 if ($result = $db->loadAssoc( )) { 248 return $this->bind($result); 249 } 250 else 251 { 252 $this->setError( $db->getErrorMsg() ); 253 return false; 254 } 255 } 256 257 /** 258 * Generic check method 259 * 260 * Can be overloaded/supplemented by the child class 261 * 262 * @access public 263 * @return boolean True if the object is ok 264 */ 265 function check() 266 { 267 return true; 268 } 269 270 /** 271 * Inserts a new row if id is zero or updates an existing row in the database table 272 * 273 * Can be overloaded/supplemented by the child class 274 * 275 * @access public 276 * @param boolean If false, null object variables are not updated 277 * @return null|string null if successful otherwise returns and error message 278 */ 279 function store( $updateNulls=false ) 280 { 281 $k = $this->_tbl_key; 282 283 if( $this->$k) 284 { 285 $ret = $this->_db->updateObject( $this->_tbl, $this, $this->_tbl_key, $updateNulls ); 286 } 287 else 288 { 289 $ret = $this->_db->insertObject( $this->_tbl, $this, $this->_tbl_key ); 290 } 291 if( !$ret ) 292 { 293 $this->setError(get_class( $this ).'::store failed - '.$this->_db->getErrorMsg()); 294 return false; 295 } 296 else 297 { 298 return true; 299 } 300 } 301 302 /** 303 * Description 304 * 305 * @access public 306 * @param $dirn 307 * @param $where 308 */ 309 function move( $dirn, $where='' ) 310 { 311 if (!in_array( 'ordering', array_keys($this->getProperties()))) 312 { 313 $this->setError( get_class( $this ).' does not support ordering' ); 314 return false; 315 } 316 317 $k = $this->_tbl_key; 318 319 $sql = "SELECT $this->_tbl_key, ordering FROM $this->_tbl"; 320 321 if ($dirn < 0) 322 { 323 $sql .= ' WHERE ordering < '.(int) $this->ordering; 324 $sql .= ($where ? ' AND '.$where : ''); 325 $sql .= ' ORDER BY ordering DESC'; 326 } 327 else if ($dirn > 0) 328 { 329 $sql .= ' WHERE ordering > '.(int) $this->ordering; 330 $sql .= ($where ? ' AND '. $where : ''); 331 $sql .= ' ORDER BY ordering'; 332 } 333 else 334 { 335 $sql .= ' WHERE ordering = '.(int) $this->ordering; 336 $sql .= ($where ? ' AND '.$where : ''); 337 $sql .= ' ORDER BY ordering'; 338 } 339 340 $this->_db->setQuery( $sql, 0, 1 ); 341 342 343 $row = null; 344 $row = $this->_db->loadObject(); 345 if (isset($row)) 346 { 347 $query = 'UPDATE '. $this->_tbl 348 . ' SET ordering = '. (int) $row->ordering 349 . ' WHERE '. $this->_tbl_key .' = '. $this->_db->Quote($this->$k) 350 ; 351 $this->_db->setQuery( $query ); 352 353 if (!$this->_db->query()) 354 { 355 $err = $this->_db->getErrorMsg(); 356 JError::raiseError( 500, $err ); 357 } 358 359 $query = 'UPDATE '.$this->_tbl 360 . ' SET ordering = '.(int) $this->ordering 361 . ' WHERE '.$this->_tbl_key.' = '.$this->_db->Quote($row->$k) 362 ; 363 $this->_db->setQuery( $query ); 364 365 if (!$this->_db->query()) 366 { 367 $err = $this->_db->getErrorMsg(); 368 JError::raiseError( 500, $err ); 369 } 370 371 $this->ordering = $row->ordering; 372 } 373 else 374 { 375 $query = 'UPDATE '. $this->_tbl 376 . ' SET ordering = '.(int) $this->ordering 377 . ' WHERE '. $this->_tbl_key .' = '. $this->_db->Quote($this->$k) 378 ; 379 $this->_db->setQuery( $query ); 380 381 if (!$this->_db->query()) 382 { 383 $err = $this->_db->getErrorMsg(); 384 JError::raiseError( 500, $err ); 385 } 386 } 387 return true; 388 } 389 390 /** 391 * Returns the ordering value to place a new item last in its group 392 * 393 * @access public 394 * @param string query WHERE clause for selecting MAX(ordering). 395 */ 396 function getNextOrder ( $where='' ) 397 { 398 if (!in_array( 'ordering', array_keys($this->getProperties()) )) 399 { 400 $this->setError( get_class( $this ).' does not support ordering' ); 401 return false; 402 } 403 404 $query = 'SELECT MAX(ordering)' . 405 ' FROM ' . $this->_tbl . 406 ($where ? ' WHERE '.$where : ''); 407 408 $this->_db->setQuery( $query ); 409 $maxord = $this->_db->loadResult(); 410 411 if ($this->_db->getErrorNum()) 412 { 413 $this->setError($this->_db->getErrorMsg()); 414 return false; 415 } 416 return $maxord + 1; 417 } 418 419 /** 420 * Compacts the ordering sequence of the selected records 421 * 422 * @access public 423 * @param string Additional where query to limit ordering to a particular subset of records 424 */ 425 function reorder( $where='' ) 426 { 427 $k = $this->_tbl_key; 428 429 if (!in_array( 'ordering', array_keys($this->getProperties() ) )) 430 { 431 $this->setError( get_class( $this ).' does not support ordering'); 432 return false; 433 } 434 435 if ($this->_tbl == '#__content_frontpage') 436 { 437 $order2 = ", content_id DESC"; 438 } 439 else 440 { 441 $order2 = ""; 442 } 443 444 $query = 'SELECT '.$this->_tbl_key.', ordering' 445 . ' FROM '. $this->_tbl 446 . ' WHERE ordering >= 0' . ( $where ? ' AND '. $where : '' ) 447 . ' ORDER BY ordering'.$order2 448 ; 449 $this->_db->setQuery( $query ); 450 if (!($orders = $this->_db->loadObjectList())) 451 { 452 $this->setError($this->_db->getErrorMsg()); 453 return false; 454 } 455 // compact the ordering numbers 456 for ($i=0, $n=count( $orders ); $i < $n; $i++) 457 { 458 if ($orders[$i]->ordering >= 0) 459 { 460 if ($orders[$i]->ordering != $i+1) 461 { 462 $orders[$i]->ordering = $i+1; 463 $query = 'UPDATE '.$this->_tbl 464 . ' SET ordering = '. (int) $orders[$i]->ordering 465 . ' WHERE '. $k .' = '. $this->_db->Quote($orders[$i]->$k) 466 ; 467 $this->_db->setQuery( $query); 468 $this->_db->query(); 469 } 470 } 471 } 472 473 return true; 474 } 475 476 /** 477 * Generic check for whether dependancies exist for this object in the db schema 478 * 479 * can be overloaded/supplemented by the child class 480 * 481 * @access public 482 * @param string $msg Error message returned 483 * @param int Optional key index 484 * @param array Optional array to compiles standard joins: format [label=>'Label',name=>'table name',idfield=>'field',joinfield=>'field'] 485 * @return true|false 486 */ 487 function canDelete( $oid=null, $joins=null ) 488 { 489 $k = $this->_tbl_key; 490 if ($oid) { 491 $this->$k = intval( $oid ); 492 } 493 494 if (is_array( $joins )) 495 { 496 $select = "$k"; 497 $join = ""; 498 foreach( $joins as $table ) 499 { 500 $select .= ', COUNT(DISTINCT '.$table['idfield'].') AS '.$table['idfield']; 501 $join .= ' LEFT JOIN '.$table['name'].' ON '.$table['joinfield'].' = '.$k; 502 } 503 504 $query = 'SELECT '. $select 505 . ' FROM '. $this->_tbl 506 . $join 507 . ' WHERE '. $k .' = '. $this->_db->Quote($this->$k) 508 . ' GROUP BY '. $k 509 ; 510 $this->_db->setQuery( $query ); 511 512 if (!$obj = $this->_db->loadObject()) 513 { 514 $this->setError($this->_db->getErrorMsg()); 515 return false; 516 } 517 $msg = array(); 518 $i = 0; 519 foreach( $joins as $table ) 520 { 521 $k = $table['idfield'] . $i; 522 if ($obj->$k) 523 { 524 $msg[] = JText::_( $table['label'] ); 525 } 526 $i++; 527 } 528 529 if (count( $msg )) 530 { 531 $this->setError("noDeleteRecord" . ": " . implode( ', ', $msg )); 532 return false; 533 } 534 else 535 { 536 return true; 537 } 538 } 539 540 return true; 541 } 542 543 /** 544 * Default delete method 545 * 546 * can be overloaded/supplemented by the child class 547 * 548 * @access public 549 * @return true if successful otherwise returns and error message 550 */ 551 function delete( $oid=null ) 552 { 553 //if (!$this->canDelete( $msg )) 554 //{ 555 // return $msg; 556 //} 557 558 $k = $this->_tbl_key; 559 if ($oid) { 560 $this->$k = intval( $oid ); 561 } 562 563 $query = 'DELETE FROM '.$this->_db->nameQuote( $this->_tbl ). 564 ' WHERE '.$this->_tbl_key.' = '. $this->_db->Quote($this->$k); 565 $this->_db->setQuery( $query ); 566 567 if ($this->_db->query()) 568 { 569 return true; 570 } 571 else 572 { 573 $this->setError($this->_db->getErrorMsg()); 574 return false; 575 } 576 } 577 578 /** 579 * Checks out a row 580 * 581 * @access public 582 * @param integer The id of the user 583 * @param mixed The primary key value for the row 584 * @return boolean True if successful, or if checkout is not supported 585 */ 586 function checkout( $who, $oid = null ) 587 { 588 if (!in_array( 'checked_out', array_keys($this->getProperties()) )) { 589 return true; 590 } 591 592 $k = $this->_tbl_key; 593 if ($oid !== null) { 594 $this->$k = $oid; 595 } 596 597 $date =& JFactory::getDate(); 598 $time = $date->toMysql(); 599 600 $query = 'UPDATE '.$this->_db->nameQuote( $this->_tbl ) . 601 ' SET checked_out = '.(int)$who.', checked_out_time = '.$this->_db->Quote($time) . 602 ' WHERE '.$this->_tbl_key.' = '. $this->_db->Quote($this->$k); 603 $this->_db->setQuery( $query ); 604 605 $this->checked_out = $who; 606 $this->checked_out_time = $time; 607 608 return $this->_db->query(); 609 } 610 611 /** 612 * Checks in a row 613 * 614 * @access public 615 * @param mixed The primary key value for the row 616 * @return boolean True if successful, or if checkout is not supported 617 */ 618 function checkin( $oid=null ) 619 { 620 if (!( 621 in_array( 'checked_out', array_keys($this->getProperties()) ) || 622 in_array( 'checked_out_time', array_keys($this->getProperties()) ) 623 )) { 624 return true; 625 } 626 627 $k = $this->_tbl_key; 628 629 if ($oid !== null) { 630 $this->$k = $oid; 631 } 632 633 if ($this->$k == NULL) { 634 return false; 635 } 636 637 $query = 'UPDATE '.$this->_db->nameQuote( $this->_tbl ). 638 ' SET checked_out = 0, checked_out_time = '.$this->_db->Quote($this->_db->getNullDate()) . 639 ' WHERE '.$this->_tbl_key.' = '. $this->_db->Quote($this->$k); 640 $this->_db->setQuery( $query ); 641 642 $this->checked_out = 0; 643 $this->checked_out_time = ''; 644 645 return $this->_db->query(); 646 } 647 648 /** 649 * Description 650 * 651 * @access public 652 * @param $oid 653 * @param $log 654 */ 655 function hit( $oid=null, $log=false ) 656 { 657 if (!in_array( 'hits', array_keys($this->getProperties()) )) { 658 return; 659 } 660 661 $k = $this->_tbl_key; 662 663 if ($oid !== null) { 664 $this->$k = intval( $oid ); 665 } 666 667 $query = 'UPDATE '. $this->_tbl 668 . ' SET hits = ( hits + 1 )' 669 . ' WHERE '. $this->_tbl_key .'='. $this->_db->Quote($this->$k); 670 $this->_db->setQuery( $query ); 671 $this->_db->query(); 672 $this->hits++; 673 } 674 675 /** 676 * Check if an item is checked out 677 * 678 * This function can be used as a static function too, when you do so you need to also provide the 679 * a value for the $against parameter. 680 * 681 * @static 682 * @access public 683 * @param integer $with The userid to preform the match with, if an item is checked out 684 * by this user the function will return false 685 * @param integer $against The userid to perform the match against when the function is used as 686 * a static function. 687 * @return boolean 688 */ 689 function isCheckedOut( $with = 0, $against = null) 690 { 691 if(isset($this) && is_a($this, 'JTable') && is_null($against)) { 692 $against = $this->get( 'checked_out' ); 693 } 694 695 //item is not checked out, or being checked out by the same user 696 if (!$against || $against == $with) { 697 return false; 698 } 699 700 $session =& JTable::getInstance('session'); 701 return $session->exists($against); 702 } 703 704 /** 705 * Generic save function 706 * 707 * @access public 708 * @param array Source array for binding to class vars 709 * @param string Filter for the order updating 710 * @param mixed An array or space separated list of fields not to bind 711 * @returns TRUE if completely successful, FALSE if partially or not succesful. 712 */ 713 function save( $source, $order_filter='', $ignore='' ) 714 { 715 if (!$this->bind( $source, $ignore )) { 716 return false; 717 } 718 if (!$this->check()) { 719 return false; 720 } 721 if (!$this->store()) { 722 return false; 723 } 724 if (!$this->checkin()) { 725 return false; 726 } 727 if ($order_filter) 728 { 729 $filter_value = $this->$order_filter; 730 $this->reorder( $order_filter ? $this->_db->nameQuote( $order_filter ).' = '.$this->_db->Quote( $filter_value ) : '' ); 731 } 732 $this->setError(''); 733 return true; 734 } 735 736 /** 737 * Generic Publish/Unpublish function 738 * 739 * @access public 740 * @param array An array of id numbers 741 * @param integer 0 if unpublishing, 1 if publishing 742 * @param integer The id of the user performnig the operation 743 * @since 1.0.4 744 */ 745 function publish( $cid=null, $publish=1, $user_id=0 ) 746 { 747 JArrayHelper::toInteger( $cid ); 748 $user_id = (int) $user_id; 749 $publish = (int) $publish; 750 $k = $this->_tbl_key; 751 752 if (count( $cid ) < 1) 753 { 754 if ($this->$k) { 755 $cid = array( $this->$k ); 756 } else { 757 $this->setError("No items selected."); 758 return false; 759 } 760 } 761 762 $cids = $k . '=' . implode( ' OR ' . $k . '=', $cid ); 763 764 $query = 'UPDATE '. $this->_tbl 765 . ' SET published = ' . (int) $publish 766 . ' WHERE ('.$cids.')' 767 ; 768 769 $checkin = in_array( 'checked_out', array_keys($this->getProperties()) ); 770 if ($checkin) 771 { 772 $query .= ' AND (checked_out = 0 OR checked_out = '.(int) $user_id.')'; 773 } 774 775 $this->_db->setQuery( $query ); 776 if (!$this->_db->query()) 777 { 778 $this->setError($this->_db->getErrorMsg()); 779 return false; 780 } 781 782 if (count( $cid ) == 1 && $checkin) 783 { 784 if ($this->_db->getAffectedRows() == 1) { 785 $this->checkin( $cid[0] ); 786 if ($this->$k == $cid[0]) { 787 $this->published = $publish; 788 } 789 } 790 } 791 $this->setError(''); 792 return true; 793 } 794 795 /** 796 * Export item list to xml 797 * 798 * @access public 799 * @param boolean Map foreign keys to text values 800 */ 801 function toXML( $mapKeysToText=false ) 802 { 803 $xml = '<record table="' . $this->_tbl . '"'; 804 805 if ($mapKeysToText) 806 { 807 $xml .= ' mapkeystotext="true"'; 808 } 809 $xml .= '>'; 810 foreach (get_object_vars( $this ) as $k => $v) 811 { 812 if (is_array($v) or is_object($v) or $v === NULL) 813 { 814 continue; 815 } 816 if ($k[0] == '_') 817 { // internal field 818 continue; 819 } 820 $xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>'; 821 } 822 $xml .= '</record>'; 823 824 return $xml; 825 } 826 827 /** 828 * Add a directory where JTable should search for table types. You may 829 * either pass a string or an array of directories. 830 * 831 * @access public 832 * @param string A path to search. 833 * @return array An array with directory elements 834 * @since 1.5 835 */ 836 function addIncludePath( $path=null ) 837 { 838 static $paths; 839 840 if (!isset($paths)) { 841 $paths = array( dirname( __FILE__ ).DS.'table' ); 842 } 843 844 // just force path to array 845 settype($path, 'array'); 846 847 if (!empty( $path ) && !in_array( $path, $paths )) 848 { 849 // loop through the path directories 850 foreach ($path as $dir) 851 { 852 // no surrounding spaces allowed! 853 $dir = trim($dir); 854 855 // add to the top of the search dirs 856 // so that custom paths are searched before core paths 857 array_unshift($paths, $dir); 858 } 859 } 860 return $paths; 861 } 862 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Mar 28 15:54:07 2012 | Cross-referenced by PHPXref 0.7.1 |