source: trunk/install/includes/database.php@ 388

Last change on this file since 388 was 336, checked in by roby, 4 years ago

Admin: prime modifiche per compatibilità con php 7.4

File size: 35.1 KB
RevLine 
[336]1 <?php
[2]2
3/************************************************************************/
4/* Eleonline */
5/* ============================================ */
6/* Installer was based on Joomla Installer */
7/************************************************************************/
8
9
10// no direct access
11defined( '_VALID_MOS' ) or die( 'Restricted access' );
12
13/**
14* Database connector class
15* @subpackage Database
16* @package PHP-Nuke
17*/
18class database {
19 /** @var string Internal variable to hold the query sql */
20 var $_sql = '';
21 /** @var int Internal variable to hold the database error number */
22 var $_errorNum = 0;
23 /** @var string Internal variable to hold the database error message */
24 var $_errorMsg = '';
25 /** @var string Internal variable to hold the prefix used on all database tables */
26 var $_table_prefix = '';
27 /** @var Internal variable to hold the connector resource */
28 var $_resource = '';
29 /** @var Internal variable to hold the last query cursor */
30 var $_cursor = null;
31 /** @var boolean Debug option */
32 var $_debug = 0;
33 /** @var int The limit for the query */
34 var $_limit = 0;
35 /** @var int The for offset for the limit */
36 var $_offset = 0;
37 /** @var int A counter for the number of queries performed by the object instance */
38 var $_ticker = 0;
39 /** @var array A log of queries */
40 var $_log = null;
41 /** @var string The null/zero date string */
42 var $_nullDate = '0000-00-00 00:00:00';
43 /** @var string Quote for named objects */
44 var $_nameQuote = '`';
45
46 /**
47 * Database object constructor
48 * @param string Database host
49 * @param string Database user name
50 * @param string Database user password
51 * @param string Database name
52 * @param string Common prefix for all tables
53 * @param boolean If true and there is an error, go offline
54 */
[336]55 function __construct( $host='localhost', $user, $pass, $db='', $table_prefix='', $goOffline=true ) {
[2]56 // perform a number of fatality checks, then die gracefully
57 if (!function_exists( 'mysql_connect' )) {
58 $mosSystemError = 1;
59 if ($goOffline) {
60 $basePath = dirname( __FILE__ );
61 include $basePath . '/../configuration.php';
62 include $basePath . '/../offline.php';
63 exit();
64 }
65 }
66 if (phpversion() < '4.2.0') {
67 if (!($this->_resource = @mysql_connect( $host, $user, $pass ))) {
68 $mosSystemError = 2;
69 if ($goOffline) {
70 $basePath = dirname( __FILE__ );
71 include $basePath . '/../configuration.php';
72 include $basePath . '/../offline.php';
73 exit();
74 }
75 }
76 } else {
77 if (!($this->_resource = @mysql_connect( $host, $user, $pass, true ))) {
78 $mosSystemError = 2;
79 if ($goOffline) {
80 $basePath = dirname( __FILE__ );
81 include $basePath . '/../configuration.php';
82 include $basePath . '/../offline.php';
83 exit();
84 }
85 }
86 }
87 if ($db != '' && !mysql_select_db( $db, $this->_resource )) {
88 $mosSystemError = 3;
89 if ($goOffline) {
90 $basePath = dirname( __FILE__ );
91 include $basePath . '/../configuration.php';
92 include $basePath . '/../offline.php';
93 exit();
94 }
95 }
96 $this->_table_prefix = $table_prefix;
97 //@mysql_query("SET NAMES 'utf8'", $this->_resource);
98 $this->_ticker = 0;
99 $this->_log = array();
100 }
101 /**
102 * @param int
103 */
104 function debug( $level ) {
105 $this->_debug = intval( $level );
106 }
107 /**
108 * @return int The error number for the most recent query
109 */
110 function getErrorNum() {
111 return $this->_errorNum;
112 }
113 /**
114 * @return string The error message for the most recent query
115 */
116 function getErrorMsg() {
117 return str_replace( array( "\n", "'" ), array( '\n', "\'" ), $this->_errorMsg );
118 }
119 /**
120 * Get a database escaped string
121 * @return string
122 */
123 function getEscaped( $text ) {
124 return mysql_escape_string( $text );
125 }
126 /**
127 * Get a quoted database escaped string
128 * @return string
129 */
130 function Quote( $text ) {
131 return '\'' . $this->getEscaped( $text ) . '\'';
132 }
133 /**
134 * Quote an identifier name (field, table, etc)
135 * @param string The name
136 * @return string The quoted name
137 */
138 function NameQuote( $s ) {
139 $q = $this->_nameQuote;
140 if (strlen( $q ) == 1) {
141 return $q . $s . $q;
142 } else {
[336]143 # return $q{0} . $s . $q{1};
144 return $q[0] . $s . $q[1];
[2]145 }
146 }
147 /**
148 * @return string The database prefix
149 */
150 function getPrefix() {
151 return $this->_table_prefix;
152 }
153 /**
154 * @return string Quoted null/zero date string
155 */
156 function getNullDate() {
157 return $this->_nullDate;
158 }
159 /**
160 * Sets the SQL query string for later execution.
161 *
162 * This function replaces a string identifier <var>$prefix</var> with the
163 * string held is the <var>_table_prefix</var> class variable.
164 *
165 * @param string The SQL query
166 * @param string The offset to start selection
167 * @param string The number of results to return
168 * @param string The common table prefix
169 */
170 function setQuery( $sql, $offset = 0, $limit = 0, $prefix='#__' ) {
171 $this->_sql = $this->replacePrefix( $sql, $prefix );
172 $this->_limit = intval( $limit );
173 $this->_offset = intval( $offset );
174 }
175
176 /**
177 * This function replaces a string identifier <var>$prefix</var> with the
178 * string held is the <var>_table_prefix</var> class variable.
179 *
180 * @param string The SQL query
181 * @param string The common table prefix
182 * @author thede, David McKinnis
183 */
184 function replacePrefix( $sql, $prefix='#__' ) {
185 $sql = trim( $sql );
186
187 $escaped = false;
188 $quoteChar = '';
189
190 $n = strlen( $sql );
191
192 $startPos = 0;
193 $literal = '';
194 while ($startPos < $n) {
195 $ip = strpos($sql, $prefix, $startPos);
196 if ($ip === false) {
197 break;
198 }
199
200 $j = strpos( $sql, "'", $startPos );
201 $k = strpos( $sql, '"', $startPos );
202 if (($k !== FALSE) && (($k < $j) || ($j === FALSE))) {
203 $quoteChar = '"';
204 $j = $k;
205 } else {
206 $quoteChar = "'";
207 }
208
209 if ($j === false) {
210 $j = $n;
211 }
212
213 $literal .= str_replace( $prefix, $this->_table_prefix, substr( $sql, $startPos, $j - $startPos ) );
214 $startPos = $j;
215
216 $j = $startPos + 1;
217
218 if ($j >= $n) {
219 break;
220 }
221
222 // quote comes first, find end of quote
223 while (TRUE) {
224 $k = strpos( $sql, $quoteChar, $j );
225 $escaped = false;
226 if ($k === false) {
227 break;
228 }
229 $l = $k - 1;
[336]230 while ($l >= 0 && $sql[$l] == '\\') { #deprecated
[2]231 $l--;
232 $escaped = !$escaped;
233 }
234 if ($escaped) {
235 $j = $k+1;
236 continue;
237 }
238 break;
239 }
240 if ($k === FALSE) {
241 // error in the query - no end quote; ignore it
242 break;
243 }
244 $literal .= substr( $sql, $startPos, $k - $startPos + 1 );
245 $startPos = $k+1;
246 }
247 if ($startPos < $n) {
248 $literal .= substr( $sql, $startPos, $n - $startPos );
249 }
250 return $literal;
251 }
252 /**
253 * @return string The current value of the internal SQL vairable
254 */
255 function getQuery() {
256 return "<pre>" . htmlspecialchars( $this->_sql ) . "</pre>";
257 }
258 /**
259 * Execute the query
260 * @return mixed A database resource if successful, FALSE if not.
261 */
262 function query() {
263 global $mosConfig_debug;
264 if ($this->_limit > 0 && $this->_offset == 0) {
265 $this->_sql .= "\nLIMIT $this->_limit";
266 } else if ($this->_limit > 0 || $this->_offset > 0) {
267 $this->_sql .= "\nLIMIT $this->_offset, $this->_limit";
268 }
269 if ($this->_debug) {
270 $this->_ticker++;
271 $this->_log[] = $this->_sql;
272 }
273 $this->_errorNum = 0;
274 $this->_errorMsg = '';
275 $this->_cursor = mysql_query( $this->_sql, $this->_resource );
276 if (!$this->_cursor) {
277 $this->_errorNum = mysql_errno( $this->_resource );
278 $this->_errorMsg = mysql_error( $this->_resource )." SQL=$this->_sql";
279 if ($this->_debug) {
280 trigger_error( mysql_error( $this->_resource ), E_USER_NOTICE );
281 //echo "<pre>" . $this->_sql . "</pre>\n";
282 if (function_exists( 'debug_backtrace' )) {
283 foreach( debug_backtrace() as $back) {
284 if (@$back['file']) {
285 echo '<br />'.$back['file'].':'.$back['line'];
286 }
287 }
288 }
289 }
290 return false;
291 }
292 return $this->_cursor;
293 }
294
295 /**
296 * @return int The number of affected rows in the previous operation
297 */
298 function getAffectedRows() {
299 return mysql_affected_rows( $this->_resource );
300 }
301
302 function query_batch( $abort_on_error=true, $p_transaction_safe = false) {
303 $this->_errorNum = 0;
304 $this->_errorMsg = '';
305 if ($p_transaction_safe) {
306 $si = mysql_get_server_info( $this->_resource );
307 preg_match_all( "/(\d+)\.(\d+)\.(\d+)/i", $si, $m );
308 if ($m[1] >= 4) {
309 $this->_sql = 'START TRANSACTION;' . $this->_sql . '; COMMIT;';
310 } else if ($m[2] >= 23 && $m[3] >= 19) {
311 $this->_sql = 'BEGIN WORK;' . $this->_sql . '; COMMIT;';
312 } else if ($m[2] >= 23 && $m[3] >= 17) {
313 $this->_sql = 'BEGIN;' . $this->_sql . '; COMMIT;';
314 }
315 }
316 $query_split = preg_split ("/[;]+/", $this->_sql);
317 $error = 0;
318 foreach ($query_split as $command_line) {
319 $command_line = trim( $command_line );
320 if ($command_line != '') {
321 $this->_cursor = mysql_query( $command_line, $this->_resource );
322 if (!$this->_cursor) {
323 $error = 1;
324 $this->_errorNum .= mysql_errno( $this->_resource ) . ' ';
325 $this->_errorMsg .= mysql_error( $this->_resource )." SQL=$command_line <br />";
326 if ($abort_on_error) {
327 return $this->_cursor;
328 }
329 }
330 }
331 }
332 return $error ? false : true;
333 }
334
335 /**
336 * Diagnostic function
337 */
338 function explain() {
339 $temp = $this->_sql;
340 $this->_sql = "EXPLAIN $this->_sql";
341 $this->query();
342
343 if (!($cur = $this->query())) {
344 return null;
345 }
346 $first = true;
347
348 $buf = "<table cellspacing=\"1\" cellpadding=\"2\" border=\"0\" bgcolor=\"#000000\" align=\"center\">";
349 $buf .= $this->getQuery();
350 while ($row = mysql_fetch_assoc( $cur )) {
351 if ($first) {
352 $buf .= "<tr>";
353 foreach ($row as $k=>$v) {
354 $buf .= "<th bgcolor=\"#ffffff\">$k</th>";
355 }
356 $buf .= "</tr>";
357 $first = false;
358 }
359 $buf .= "<tr>";
360 foreach ($row as $k=>$v) {
361 $buf .= "<td bgcolor=\"#ffffff\">$v</td>";
362 }
363 $buf .= "</tr>";
364 }
365 $buf .= "</table><br />&nbsp;";
366 mysql_free_result( $cur );
367
368 $this->_sql = $temp;
369
370 return "<div style=\"background-color:#FFFFCC\" align=\"left\">$buf</div>";
371 }
372 /**
373 * @return int The number of rows returned from the most recent query.
374 */
375 function getNumRows( $cur=null ) {
376 return mysql_num_rows( $cur ? $cur : $this->_cursor );
377 }
378
379 /**
380 * This method loads the first field of the first row returned by the query.
381 *
382 * @return The value returned in the query or null if the query failed.
383 */
384 function loadResult() {
385 if (!($cur = $this->query())) {
386 return null;
387 }
388 $ret = null;
389 if ($row = mysql_fetch_row( $cur )) {
390 $ret = $row[0];
391 }
392 mysql_free_result( $cur );
393 return $ret;
394 }
395 /**
396 * Load an array of single field results into an array
397 */
398 function loadResultArray($numinarray = 0) {
399 if (!($cur = $this->query())) {
400 return null;
401 }
402 $array = array();
403 while ($row = mysql_fetch_row( $cur )) {
404 $array[] = $row[$numinarray];
405 }
406 mysql_free_result( $cur );
407 return $array;
408 }
409 /**
410 * Load a assoc list of database rows
411 * @param string The field name of a primary key
412 * @return array If <var>key</var> is empty as sequential list of returned records.
413 */
414 function loadAssocList( $key='' ) {
415 if (!($cur = $this->query())) {
416 return null;
417 }
418 $array = array();
419 while ($row = mysql_fetch_assoc( $cur )) {
420 if ($key) {
421 $array[$row[$key]] = $row;
422 } else {
423 $array[] = $row;
424 }
425 }
426 mysql_free_result( $cur );
427 return $array;
428 }
429 /**
430 * This global function loads the first row of a query into an object
431 *
432 * If an object is passed to this function, the returned row is bound to the existing elements of <var>object</var>.
433 * If <var>object</var> has a value of null, then all of the returned query fields returned in the object.
434 * @param string The SQL query
435 * @param object The address of variable
436 */
437 function loadObject( &$object ) {
438 if ($object != null) {
439 if (!($cur = $this->query())) {
440 return false;
441 }
442 if ($array = mysql_fetch_assoc( $cur )) {
443 mysql_free_result( $cur );
444 mosBindArrayToObject( $array, $object, null, null, false );
445 return true;
446 } else {
447 return false;
448 }
449 } else {
450 if ($cur = $this->query()) {
451 if ($object = mysql_fetch_object( $cur )) {
452 mysql_free_result( $cur );
453 return true;
454 } else {
455 $object = null;
456 return false;
457 }
458 } else {
459 return false;
460 }
461 }
462 }
463 /**
464 * Load a list of database objects
465 * @param string The field name of a primary key
466 * @return array If <var>key</var> is empty as sequential list of returned records.
467 * If <var>key</var> is not empty then the returned array is indexed by the value
468 * the database key. Returns <var>null</var> if the query fails.
469 */
470 function loadObjectList( $key='' ) {
471 if (!($cur = $this->query())) {
472 return null;
473 }
474 $array = array();
475 while ($row = mysql_fetch_object( $cur )) {
476 if ($key) {
477 $array[$row->$key] = $row;
478 } else {
479 $array[] = $row;
480 }
481 }
482 mysql_free_result( $cur );
483 return $array;
484 }
485 /**
486 * @return The first row of the query.
487 */
488 function loadRow() {
489 if (!($cur = $this->query())) {
490 return null;
491 }
492 $ret = null;
493 if ($row = mysql_fetch_row( $cur )) {
494 $ret = $row;
495 }
496 mysql_free_result( $cur );
497 return $ret;
498 }
499 /**
500 * Load a list of database rows (numeric column indexing)
501 * @param string The field name of a primary key
502 * @return array If <var>key</var> is empty as sequential list of returned records.
503 * If <var>key</var> is not empty then the returned array is indexed by the value
504 * the database key. Returns <var>null</var> if the query fails.
505 */
506 function loadRowList( $key=null ) {
507 if (!($cur = $this->query())) {
508 return null;
509 }
510 $array = array();
511 while ($row = mysql_fetch_row( $cur )) {
512 if ( !is_null( $key ) ) {
513 $array[$row[$key]] = $row;
514 } else {
515 $array[] = $row;
516 }
517 }
518 mysql_free_result( $cur );
519 return $array;
520 }
521 /**
522 * Document::db_insertObject()
523 *
524 * { Description }
525 *
526 * @param [type] $keyName
527 * @param [type] $verbose
528 */
529 function insertObject( $table, &$object, $keyName = NULL, $verbose=false ) {
530 $fmtsql = "INSERT INTO $table ( %s ) VALUES ( %s ) ";
531 $fields = array();
532 foreach (get_object_vars( $object ) as $k => $v) {
533 if (is_array($v) or is_object($v) or $v === NULL) {
534 continue;
535 }
536 if ($k[0] == '_') { // internal field
537 continue;
538 }
539 $fields[] = $this->NameQuote( $k );
540 $values[] = $this->Quote( $v );
541 }
542 $this->setQuery( sprintf( $fmtsql, implode( ",", $fields ) , implode( ",", $values ) ) );
543 ($verbose) && print "$sql<br />\n";
544 if (!$this->query()) {
545 return false;
546 }
547 $id = mysql_insert_id( $this->_resource );
548 ($verbose) && print "id=[$id]<br />\n";
549 if ($keyName && $id) {
550 $object->$keyName = $id;
551 }
552 return true;
553 }
554
555 /**
556 * Document::db_updateObject()
557 *
558 * { Description }
559 *
560 * @param [type] $updateNulls
561 */
562 function updateObject( $table, &$object, $keyName, $updateNulls=true ) {
563 $fmtsql = "UPDATE $table SET %s WHERE %s";
564 $tmp = array();
565 foreach (get_object_vars( $object ) as $k => $v) {
566 if( is_array($v) or is_object($v) or $k[0] == '_' ) { // internal or NA field
567 continue;
568 }
569 if( $k == $keyName ) { // PK not to be updated
570 $where = $keyName . '=' . $this->Quote( $v );
571 continue;
572 }
573 if ($v === NULL && !$updateNulls) {
574 continue;
575 }
576 if( $v == '' ) {
577 $val = "''";
578 } else {
579 $val = $this->Quote( $v );
580 }
581 $tmp[] = $this->NameQuote( $k ) . '=' . $val;
582 }
583 $this->setQuery( sprintf( $fmtsql, implode( ",", $tmp ) , $where ) );
584 return $this->query();
585 }
586
587 /**
588 * @param boolean If TRUE, displays the last SQL statement sent to the database
589 * @return string A standised error message
590 */
591 function stderr( $showSQL = false ) {
592 return "DB function failed with error number $this->_errorNum"
593 ."<br /><font color=\"red\">$this->_errorMsg</font>"
594 .($showSQL ? "<br />SQL = <pre>$this->_sql</pre>" : '');
595 }
596
597 function insertid() {
598 return mysql_insert_id( $this->_resource );
599 }
600
601 function getVersion() {
602 return mysql_get_server_info( $this->_resource );
603 }
604
605 /**
606 * @return array A list of all the tables in the database
607 */
608 function getTableList() {
609 $this->setQuery( 'SHOW TABLES' );
610 return $this->loadResultArray();
611 }
612 /**
613 * @param array A list of table names
614 * @return array A list the create SQL for the tables
615 */
616 function getTableCreate( $tables ) {
617 $result = array();
618
619 foreach ($tables as $tblval) {
620 $this->setQuery( 'SHOW CREATE table ' . $this->getEscaped( $tblval ) );
621 $rows = $this->loadRowList();
622 foreach ($rows as $row) {
623 $result[$tblval] = $row[1];
624 }
625 }
626
627 return $result;
628 }
629 /**
630 * @param array A list of table names
631 * @return array An array of fields by table
632 */
633 function getTableFields( $tables ) {
634 $result = array();
635
636 foreach ($tables as $tblval) {
637 $this->setQuery( 'SHOW FIELDS FROM ' . $tblval );
638 $fields = $this->loadObjectList();
639 foreach ($fields as $field) {
640 $result[$tblval][$field->Field] = preg_replace("/[(0-9)]/",'', $field->Type );
641 }
642 }
643
644 return $result;
645 }
646
647 /**
648 * Fudge method for ADOdb compatibility
649 */
650 function GenID( $foo1=null, $foo2=null ) {
651 return '0';
652 }
653}
654
655/**
656* mosDBTable Abstract Class.
657* @abstract
658* @package PHP-Nuke
659* @subpackage Database
660*
661* Parent classes to all database derived objects. Customisation will generally
662* not involve tampering with this object.
663* @package PHP-Nuke
664* @author Andrew Eddie <eddieajau@users.sourceforge.net
665*/
666class mosDBTable {
667 /** @var string Name of the table in the db schema relating to child class */
668 var $_tbl = '';
669 /** @var string Name of the primary key field in the table */
670 var $_tbl_key = '';
671 /** @var string Error message */
672 var $_error = '';
673 /** @var mosDatabase Database connector */
674 var $_db = null;
675
676 /**
677 * Object constructor to set table and key field
678 *
679 * Can be overloaded/supplemented by the child class
680 * @param string $table name of the table in the db schema relating to child class
681 * @param string $key name of the primary key field in the table
682 */
[336]683 function __construct( $table, $key, &$db ) {
[2]684 $this->_tbl = $table;
685 $this->_tbl_key = $key;
686 $this->_db =& $db;
687 }
688
689 /**
690 * Returns an array of public properties
691 * @return array
692 */
693 function getPublicProperties() {
694 static $cache = null;
695 if (is_null( $cache )) {
696 $cache = array();
697 foreach (get_class_vars( get_class( $this ) ) as $key=>$val) {
698 if (substr( $key, 0, 1 ) != '_') {
699 $cache[] = $key;
700 }
701 }
702 }
703 return $cache;
704 }
705 /**
706 * Filters public properties
707 * @access protected
708 * @param array List of fields to ignore
709 */
710 function filter( $ignoreList=null ) {
711 $ignore = is_array( $ignoreList );
712
713 $iFilter = new InputFilter();
714 foreach ($this->getPublicProperties() as $k) {
715 if ($ignore && in_array( $k, $ignoreList ) ) {
716 continue;
717 }
718 $this->$k = $iFilter->process( $this->$k );
719 }
720 }
721 /**
722 * @return string Returns the error message
723 */
724 function getError() {
725 return $this->_error;
726 }
727 /**
728 * Gets the value of the class variable
729 * @param string The name of the class variable
730 * @return mixed The value of the class var (or null if no var of that name exists)
731 */
732 function get( $_property ) {
733 if(isset( $this->$_property )) {
734 return $this->$_property;
735 } else {
736 return null;
737 }
738 }
739
740 /**
741 * Set the value of the class variable
742 * @param string The name of the class variable
743 * @param mixed The value to assign to the variable
744 */
745 function set( $_property, $_value ) {
746 $this->$_property = $_value;
747 }
748
749 /**
750 * Resets public properties
751 * @param mixed The value to set all properties to, default is null
752 */
753 function reset( $value=null ) {
754 $keys = $this->getPublicProperties();
755 foreach ($keys as $k) {
756 $this->$k = $value;
757 }
758 }
759 /**
760 * binds a named array/hash to this object
761 *
762 * can be overloaded/supplemented by the child class
763 * @param array $hash named array
764 * @return null|string null is operation was satisfactory, otherwise returns an error
765 */
766 function bind( $array, $ignore='' ) {
767 if (!is_array( $array )) {
768 $this->_error = strtolower(get_class( $this ))."::bind failed.";
769 return false;
770 } else {
771 return mosBindArrayToObject( $array, $this, $ignore );
772 }
773 }
774
775 /**
776 * binds an array/hash to this object
777 * @param int $oid optional argument, if not specifed then the value of current key is used
778 * @return any result from the database operation
779 */
780 function load( $oid=null ) {
781 $k = $this->_tbl_key;
782
783 if ($oid !== null) {
784 $this->$k = $oid;
785 }
786
787 $oid = $this->$k;
788
789 if ($oid === null) {
790 return false;
791 }
792
793 $class_vars = get_class_vars(get_class($this));
794 foreach ($class_vars as $name => $value) {
795 if (($name != $k) and ($name != "_db") and ($name != "_tbl") and ($name != "_tbl_key")) {
796 $this->$name = $value;
797 }
798 }
799
800 $this->reset();
801
802 $query = "SELECT *"
803 . "\n FROM $this->_tbl"
804 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $oid )
805 ;
806 $this->_db->setQuery( $query );
807
808 return $this->_db->loadObject( $this );
809 }
810
811 /**
812 * generic check method
813 *
814 * can be overloaded/supplemented by the child class
815 * @return boolean True if the object is ok
816 */
817 function check() {
818 return true;
819 }
820
821 /**
822 * Inserts a new row if id is zero or updates an existing row in the database table
823 *
824 * Can be overloaded/supplemented by the child class
825 * @param boolean If false, null object variables are not updated
826 * @return null|string null if successful otherwise returns and error message
827 */
828 function store( $updateNulls=false ) {
829 $k = $this->_tbl_key;
830
831 if ($this->$k != 0) {
832 $ret = $this->_db->updateObject( $this->_tbl, $this, $this->_tbl_key, $updateNulls );
833 } else {
834 $ret = $this->_db->insertObject( $this->_tbl, $this, $this->_tbl_key );
835 }
836 if( !$ret ) {
837 $this->_error = strtolower(get_class( $this ))."::store failed <br />" . $this->_db->getErrorMsg();
838 return false;
839 } else {
840 return true;
841 }
842 }
843 /**
844 */
845 function move( $dirn, $where='' ) {
846 $k = $this->_tbl_key;
847
848 $sql = "SELECT $this->_tbl_key, ordering FROM $this->_tbl";
849
850 if ($dirn < 0) {
851 $sql .= "\n WHERE ordering < " . (int) $this->ordering;
852 $sql .= ($where ? "\n AND $where" : '');
853 $sql .= "\n ORDER BY ordering DESC";
854 $sql .= "\n LIMIT 1";
855 } else if ($dirn > 0) {
856 $sql .= "\n WHERE ordering > " . (int) $this->ordering;
857 $sql .= ($where ? "\n AND $where" : '');
858 $sql .= "\n ORDER BY ordering";
859 $sql .= "\n LIMIT 1";
860 } else {
861 $sql .= "\nWHERE ordering = " . (int) $this->ordering;
862 $sql .= ($where ? "\n AND $where" : '');
863 $sql .= "\n ORDER BY ordering";
864 $sql .= "\n LIMIT 1";
865 }
866
867 $this->_db->setQuery( $sql );
868//echo 'A: ' . $this->_db->getQuery();
869
870
871 $row = null;
872 if ($this->_db->loadObject( $row )) {
873 $query = "UPDATE $this->_tbl"
874 . "\n SET ordering = " . (int) $row->ordering
875 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
876 ;
877 $this->_db->setQuery( $query );
878
879 if (!$this->_db->query()) {
880 $err = $this->_db->getErrorMsg();
881 die( $err );
882 }
883//echo 'B: ' . $this->_db->getQuery();
884
885 $query = "UPDATE $this->_tbl"
886 . "\n SET ordering = " . (int) $this->ordering
887 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $row->$k )
888 ;
889 $this->_db->setQuery( $query );
890//echo 'C: ' . $this->_db->getQuery();
891
892 if (!$this->_db->query()) {
893 $err = $this->_db->getErrorMsg();
894 die( $err );
895 }
896
897 $this->ordering = $row->ordering;
898 } else {
899 $query = "UPDATE $this->_tbl"
900 . "\n SET ordering = " . (int) $this->ordering
901 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
902 ;
903 $this->_db->setQuery( $query );
904//echo 'D: ' . $this->_db->getQuery();
905
906
907 if (!$this->_db->query()) {
908 $err = $this->_db->getErrorMsg();
909 die( $err );
910 }
911 }
912 }
913 /**
914 * Compacts the ordering sequence of the selected records
915 * @param string Additional where query to limit ordering to a particular subset of records
916 */
917 function updateOrder( $where='' ) {
918 $k = $this->_tbl_key;
919
920 if (!array_key_exists( 'ordering', get_class_vars( strtolower(get_class( $this )) ) )) {
921 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support ordering.";
922 return false;
923 }
924
925 if ($this->_tbl == "#__content_frontpage") {
926 $order2 = ", content_id DESC";
927 } else {
928 $order2 = '';
929 }
930
931 $query = "SELECT $this->_tbl_key, ordering"
932 . "\n FROM $this->_tbl"
933 . ( $where ? "\n WHERE $where" : '' )
934 . "\n ORDER BY ordering$order2 "
935 ;
936 $this->_db->setQuery( $query );
937 if (!($orders = $this->_db->loadObjectList())) {
938 $this->_error = $this->_db->getErrorMsg();
939 return false;
940 }
941 // first pass, compact the ordering numbers
942 for ($i=0, $n=count( $orders ); $i < $n; $i++) {
943 if ($orders[$i]->ordering >= 0) {
944 $orders[$i]->ordering = $i+1;
945 }
946 }
947
948 $shift = 0;
949 $n=count( $orders );
950 for ($i=0; $i < $n; $i++) {
951 //echo "i=$i id=".$orders[$i]->$k." order=".$orders[$i]->ordering;
952 if ($orders[$i]->$k == $this->$k) {
953 // place 'this' record in the desired location
954 $orders[$i]->ordering = min( $this->ordering, $n );
955 $shift = 1;
956 } else if ($orders[$i]->ordering >= $this->ordering && $this->ordering > 0) {
957 $orders[$i]->ordering++;
958 }
959 }
960 //echo '<pre>';print_r($orders);echo '</pre>';
961 // compact once more until I can find a better algorithm
962 for ($i=0, $n=count( $orders ); $i < $n; $i++) {
963 if ($orders[$i]->ordering >= 0) {
964 $orders[$i]->ordering = $i+1;
965 $query = "UPDATE $this->_tbl"
966 . "\n SET ordering = " . (int) $orders[$i]->ordering
967 . "\n WHERE $k = " . $this->_db->Quote( $orders[$i]->$k )
968 ;
969 $this->_db->setQuery( $query);
970 $this->_db->query();
971 //echo '<br />'.$this->_db->getQuery();
972 }
973 }
974
975 // if we didn't reorder the current record, make it last
976 if ($shift == 0) {
977 $order = $n+1;
978 $query = "UPDATE $this->_tbl"
979 . "\n SET ordering = " . (int) $order
980 . "\n WHERE $k = " . $this->_db->Quote( $this->$k )
981 ;
982 $this->_db->setQuery( $query );
983 $this->_db->query();
984 //echo '<br />'.$this->_db->getQuery();
985 }
986 return true;
987 }
988 /**
989 * Generic check for whether dependancies exist for this object in the db schema
990 *
991 * can be overloaded/supplemented by the child class
992 * @param string $msg Error message returned
993 * @param int Optional key index
994 * @param array Optional array to compiles standard joins: format [label=>'Label',name=>'table name',idfield=>'field',joinfield=>'field']
995 * @return true|false
996 */
997 function canDelete( $oid=null, $joins=null ) {
998 $k = $this->_tbl_key;
999 if ($oid) {
1000 $this->$k = intval( $oid );
1001 }
1002 if (is_array( $joins )) {
1003 $select = $k;
1004 $join = '';
1005 foreach( $joins as $table ) {
1006 $tblName = $this->getEscaped( $table['name'] );
1007 $idField = $this->getEscaped( $table['idfield'] );
1008 $jnField = $this->getEscaped( $table['joinfield'] );
1009 $select .= ",\n COUNT(DISTINCT `$tblName`.`$idField`) AS `count_".substr($tblName, 3)."_$idField`";
1010 $join .= "\n LEFT JOIN `$tblName` ON `$tblName`.`$jnField` = `$this->_tbl`.`$k`";
1011 }
1012
1013 $query = "SELECT $select"
1014 . "\n FROM `$this->_tbl`"
1015 . $join
1016 . "\n WHERE `$this->_tbl`.`$k` = ". (int) $this->$k
1017 . "\n GROUP BY `$this->_tbl`.`$k`"
1018 ;
1019 $this->_db->setQuery( $query );
1020
1021 $obj = null;
1022 if (!$this->_db->loadObject($obj)) {
1023 $this->_error = $this->_db->getErrorMsg();
1024 return false;
1025 }
1026 $msg = array();
1027 foreach( $joins as $table ) {
1028 $tblName = $this->getEscaped( $table['name'] );
1029 $idField = $this->getEscaped( $table['idfield'] );
1030 $k = 'count_'.substr($tblName, 3).'_'.$idField;
1031 if ($obj->$k) {
1032 $msg[] = $table['label'];
1033 }
1034 }
1035
1036 if (count( $msg )) {
1037 $this->_error = "noDeleteRecord" . ": " . implode( ', ', $msg );
1038 return false;
1039 } else {
1040 return true;
1041 }
1042 }
1043
1044 return true;
1045 }
1046
1047 /**
1048 * Default delete method
1049 *
1050 * can be overloaded/supplemented by the child class
1051 * @return true if successful otherwise returns and error message
1052 */
1053 function delete( $oid=null ) {
1054 //if (!$this->canDelete( $msg )) {
1055 // return $msg;
1056 //}
1057
1058 $k = $this->_tbl_key;
1059 if ($oid) {
1060 $this->$k = intval( $oid );
1061 }
1062
1063 $query = "DELETE FROM $this->_tbl"
1064 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
1065 ;
1066 $this->_db->setQuery( $query );
1067
1068 if ($this->_db->query()) {
1069 return true;
1070 } else {
1071 $this->_error = $this->_db->getErrorMsg();
1072 return false;
1073 }
1074 }
1075
1076 /**
1077 * Checks out an object
1078 * @param int User id
1079 * @param int Object id
1080 */
1081 function checkout( $user_id, $oid=null ) {
1082 if (!array_key_exists( 'checked_out', get_class_vars( strtolower(get_class( $this )) ) )) {
1083 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support checkouts.";
1084 return false;
1085 }
1086 $k = $this->_tbl_key;
1087 if ($oid !== null) {
1088 $this->$k = $oid;
1089 }
1090
1091 $time = date( 'Y-m-d H:i:s' );
1092 if (intval( $user_id )) {
1093 $user_id = intval( $user_id );
1094 // new way of storing editor, by id
1095 $query = "UPDATE $this->_tbl"
1096 . "\n SET checked_out = $user_id, checked_out_time = " . $this->_db->Quote( $time )
1097 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
1098 ;
1099 $this->_db->setQuery( $query );
1100
1101 $this->checked_out = $user_id;
1102 $this->checked_out_time = $time;
1103 } else {
1104 $user_id = $this->_db->Quote( $user_id );
1105 // old way of storing editor, by name
1106 $query = "UPDATE $this->_tbl"
1107 . "\n SET checked_out = 1, checked_out_time = " . $this->_db->Quote( $time ) . ", editor = $user_id"
1108 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
1109 ;
1110 $this->_db->setQuery( $query );
1111
1112 $this->checked_out = 1;
1113 $this->checked_out_time = $time;
1114 $this->checked_out_editor = $user_id;
1115 }
1116
1117 return $this->_db->query();
1118 }
1119
1120 /**
1121 * Checks in an object
1122 * @param int Object id
1123 */
1124 function checkin( $oid=null ) {
1125 if (!array_key_exists( 'checked_out', get_class_vars( strtolower(get_class( $this )) ) )) {
1126 $this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support checkin.";
1127 return false;
1128 }
1129 $k = $this->_tbl_key;
1130 $nullDate = $this->_db->getNullDate();
1131
1132 if ($oid !== null) {
1133 $this->$k = intval( $oid );
1134 }
1135 if ($this->$k == NULL) {
1136 return false;
1137 }
1138
1139 $query = "UPDATE $this->_tbl"
1140 . "\n SET checked_out = 0, checked_out_time = " . $this->_db->Quote( $nullDate )
1141 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
1142 ;
1143 $this->_db->setQuery( $query );
1144
1145 $this->checked_out = 0;
1146 $this->checked_out_time = '';
1147
1148 return $this->_db->query();
1149 }
1150
1151 /**
1152 * Increments the hit counter for an object
1153 * @param int Object id
1154 */
1155 function hit( $oid=null ) {
1156 global $mosConfig_enable_log_items;
1157
1158 $k = $this->_tbl_key;
1159 if ($oid !== null) {
1160 $this->$k = intval( $oid );
1161 }
1162
1163 $query = "UPDATE $this->_tbl"
1164 . "\n SET hits = ( hits + 1 )"
1165 . "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->id )
1166 ;
1167 $this->_db->setQuery( $query );
1168 $this->_db->query();
1169
1170 if (@$mosConfig_enable_log_items) {
1171 $now = date( 'Y-m-d' );
1172 $query = "SELECT hits"
1173 . "\n FROM #__core_log_items"
1174 . "\n WHERE time_stamp = " . $this->_db->Quote( $now )
1175 . "\n AND item_table = " . $this->_db->Quote( $this->_tbl )
1176 . "\n AND item_id = " . $this->_db->Quote( $this->$k )
1177 ;
1178 $this->_db->setQuery( $query );
1179 $hits = intval( $this->_db->loadResult() );
1180 if ($hits) {
1181 $query = "UPDATE #__core_log_items"
1182 . "\n SET hits = ( hits + 1 )"
1183 . "\n WHERE time_stamp = " . $this->_db->Quote( $now )
1184 . "\n AND item_table = " . $this->_db->Quote( $this->_tbl )
1185 . "\n AND item_id = " . $this->_db->Quote( $this->$k )
1186 ;
1187 $this->_db->setQuery( $query );
1188 $this->_db->query();
1189 } else {
1190 $query = "INSERT INTO #__core_log_items"
1191 . "\n VALUES ( " . $this->_db->Quote( $now ) . ", " . $this->_db->Quote( $this->_tbl ) . ", " . $this->_db->Quote( $this->$k ) . ", 1 )"
1192 ;
1193 $this->_db->setQuery( $query );
1194 $this->_db->query();
1195 }
1196 }
1197 }
1198
1199 /**
1200 * Tests if item is checked out
1201 * @param int A user id
1202 * @return boolean
1203 */
1204 function isCheckedOut( $user_id=0 ) {
1205 if ($user_id) {
1206 return ($this->checked_out && $this->checked_out != $user_id);
1207 } else {
1208 return $this->checked_out;
1209 }
1210 }
1211
1212 /**
1213 * Generic save function
1214 * @param array Source array for binding to class vars
1215 * @param string Filter for the order updating
1216 * @returns TRUE if completely successful, FALSE if partially or not succesful
1217 * NOTE: Filter will be deprecated in verion 1.1
1218 */
1219 function save( $source, $order_filter='' ) {
1220 if (!$this->bind( $source )) {
1221 return false;
1222 }
1223 if (!$this->check()) {
1224 return false;
1225 }
1226 if (!$this->store()) {
1227 return false;
1228 }
1229 if (!$this->checkin()) {
1230 return false;
1231 }
1232
1233 if ($order_filter) {
1234 $filter_value = $this->$order_filter;
1235 $this->updateOrder( $order_filter ? "`$order_filter` = " . $this->_db->Quote( $filter_value ) : '' );
1236 }
1237 $this->_error = '';
1238 return true;
1239 }
1240
1241 /**
1242 * @deprecated As of 1.0.3, replaced by publish
1243 */
1244 function publish_array( $cid=null, $publish=1, $user_id=0 ) {
1245 $this->publish( $cid, $publish, $user_id );
1246 }
1247
1248 /**
1249 * Generic Publish/Unpublish function
1250 * @param array An array of id numbers
1251 * @param integer 0 if unpublishing, 1 if publishing
1252 * @param integer The id of the user performnig the operation
1253 * @since 1.0.4
1254 */
1255 function publish( $cid=null, $publish=1, $user_id=0 ) {
1256 mosArrayToInts( $cid, array() );
1257 $user_id = (int) $user_id;
1258 $publish = (int) $publish;
1259 $k = $this->_tbl_key;
1260
1261 if (count( $cid ) < 1) {
1262 $this->_error = "Nessun elemento selezionato.";
1263 return false;
1264 }
1265
1266 $cids = $this->_tbl_key . '=' . implode( ' OR ' . $this->_tbl_key . '=', $cid );
1267
1268 $query = "UPDATE $this->_tbl"
1269 . "\n SET published = " . (int) $publish
1270 . "\n WHERE ($cids)"
1271 . "\n AND (checked_out = 0 OR checked_out = " . (int) $user_id . ")"
1272 ;
1273 $this->_db->setQuery( $query );
1274 if (!$this->_db->query()) {
1275 $this->_error = $this->_db->getErrorMsg();
1276 return false;
1277 }
1278
1279 if (count( $cid ) == 1) {
1280 $this->checkin( $cid[0] );
1281 }
1282 $this->_error = '';
1283 return true;
1284 }
1285
1286 /**
1287 * Export item list to xml
1288 * @param boolean Map foreign keys to text values
1289 */
1290 function toXML( $mapKeysToText=false ) {
1291 $xml = '<record table="' . $this->_tbl . '"';
1292
1293 if ($mapKeysToText) {
1294 $xml .= ' mapkeystotext="true"';
1295 }
1296 $xml .= '>';
1297 foreach (get_object_vars( $this ) as $k => $v) {
1298 if (is_array($v) or is_object($v) or $v === NULL) {
1299 continue;
1300 }
1301 if ($k[0] == '_') { // internal field
1302 continue;
1303 }
1304 $xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>';
1305 }
1306 $xml .= '</record>';
1307
1308 return $xml;
1309 }
1310}
1311?>
Note: See TracBrowser for help on using the repository browser.