2002-02-18 07:52:33 +01:00
< ? php
2006-04-20 19:12:30 +02:00
/**
* eGroupWare generalized SQL Storage Object
*
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ package etemplate
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker @ outdoor - training . de >
2009-01-17 04:36:58 +01:00
* @ copyright 2002 - 9 by RalfBecker @ outdoor - training . de
2006-04-20 19:12:30 +02:00
* @ version $Id $
*/
2002-02-18 07:52:33 +01:00
2005-02-13 14:03:36 +01:00
/**
* generalized SQL Storage Object
*
* the class can be used in following ways :
* 1 ) by calling the constructor with an app and table - name or
* 2 ) by setting the following documented class - vars in a class derifed from this one
* Of cause can you derife the class and call the constructor with params .
*
* @ package etemplate
2005-11-10 06:15:06 +01:00
* @ subpackage api
2005-02-13 14:03:36 +01:00
* @ author RalfBecker - AT - outdoor - training . de
2005-04-08 20:30:32 +02:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
2005-02-13 14:03:36 +01:00
*/
2002-02-18 07:52:33 +01:00
class so_sql
{
2008-04-26 09:49:01 +02:00
/**
* need to be set in the derived class to the db - table - name
*
2006-08-29 06:19:38 +02:00
* @ var string
2005-02-13 14:03:36 +01:00
*/
var $table_name ;
/**
2006-08-29 06:19:38 +02:00
* db - col - name of autoincrement id or ''
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var string
2005-02-13 14:03:36 +01:00
*/
var $autoinc_id = '' ;
/**
2006-08-29 06:19:38 +02:00
* all cols in data which are not ( direct ) in the db , for data_merge
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-13 14:03:36 +01:00
*/
var $non_db_cols = array ();
/**
2006-08-29 06:19:38 +02:00
* 4 turns on the so_sql debug - messages , default 0
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var int
2005-02-13 14:03:36 +01:00
*/
var $debug = 0 ;
/**
2006-08-29 06:19:38 +02:00
* string to be written to db if a col - value is '' , eg . " '' " or 'NULL' ( default )
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var string
2005-02-13 14:03:36 +01:00
*/
var $empty_on_write = 'NULL' ;
2005-02-27 22:31:10 +01:00
/**
2006-08-29 06:19:38 +02:00
* total number of entries of last search with start != false
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var int / boolean
2005-02-27 22:31:10 +01:00
*/
var $total = false ;
/**
2008-03-13 12:08:54 +01:00
* protected instance or reference ( depeding on $no_clone param of constructor ) of the db - object
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var egw_db
2005-02-27 22:31:10 +01:00
*/
2008-03-13 12:08:54 +01:00
protected $db ;
2005-02-27 22:31:10 +01:00
/**
2006-08-29 06:19:38 +02:00
* unique keys / index , set by derived class or via so_sql ( $app , $table )
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-27 22:31:10 +01:00
*/
2002-02-18 07:52:33 +01:00
var $db_uni_cols = array ();
2005-02-27 22:31:10 +01:00
/**
2006-08-29 06:19:38 +02:00
* db - col - name / internal - name pairs , set by derived calls or via so_sql ( $app , $table )
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-27 22:31:10 +01:00
*/
var $db_key_cols = array ();
/**
2008-04-26 09:49:01 +02:00
* db - col - name / internal - name pairs , set by derived calls or via so_sql ( $app , $table )
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-27 22:31:10 +01:00
*/
var $db_data_cols = array ();
/**
* @ var array $db_cols all columns = $db_key_cols + $db_data_cols , set in the constructor
*/
var $db_cols = array ();
2006-04-19 10:03:28 +02:00
/**
2006-08-29 06:19:38 +02:00
* eGW table definition
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2006-04-19 10:03:28 +02:00
*/
var $table_def = array ();
2008-03-13 12:08:54 +01:00
/**
* Appname to use in all queries , set via constructor
*
* @ var string
*/
var $app ;
2005-02-27 22:31:10 +01:00
/**
2006-08-29 06:19:38 +02:00
* holds the content of all columns
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-27 22:31:10 +01:00
*/
var $data = array ();
/**
2007-12-04 02:13:53 +01:00
* Timestaps that need to be adjusted to user - time on reading or saving
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ var array
2005-02-27 22:31:10 +01:00
*/
2007-12-04 02:13:53 +01:00
var $timestamps = array ();
/**
2008-04-26 09:49:01 +02:00
* Offset in secconds between user and server - time , it need to be add to a server - time to get the user - time
2007-12-04 02:13:53 +01:00
* or substracted from a user - time to get the server - time
2008-04-26 09:49:01 +02:00
*
2007-12-04 02:13:53 +01:00
* @ var int
*/
var $tz_offset_s ;
/**
* Current time as timestamp in user - time
2008-04-26 09:49:01 +02:00
*
2007-12-04 02:13:53 +01:00
* @ var int
*/
var $now ;
2002-02-18 07:52:33 +01:00
2005-02-13 14:03:36 +01:00
/**
* constructor of the class
*
* NEED to be called from the constructor of the derived class ! ! !
*
* @ param string $app should be set if table - defs to be read from < app >/ setup / tables_current . inc . php
* @ param string $table should be set if table - defs to be read from < app >/ setup / tables_current . inc . php
2009-05-03 20:36:38 +02:00
* @ param egw_db $db database object , if not the one in $GLOBALS [ 'egw' ] -> db should be used , eg . for an other database
2006-04-19 10:03:28 +02:00
* @ param string $colum_prefix = '' column prefix to automatic remove from the column - name , if the column name starts with it
2008-04-26 09:49:01 +02:00
* @ param boolean $no_clone = false can we avoid to clone the db - object , default no
2008-03-13 12:08:54 +01:00
* new code using appnames and foreach ( select ( ... , $app ) can set it to avoid an extra instance of the db object
2008-04-26 09:49:01 +02:00
*
2006-08-29 06:19:38 +02:00
* @ return so_sql
2005-02-13 14:03:36 +01:00
*/
2008-05-26 10:27:24 +02:00
function __construct ( $app = '' , $table = '' , $db = null , $column_prefix = '' , $no_clone = false )
2002-02-18 07:52:33 +01:00
{
2008-03-13 12:08:54 +01:00
if ( $no_clone )
{
$this -> db = is_object ( $db ) ? $db : $GLOBALS [ 'egw' ] -> db ;
}
else
{
$this -> db = is_object ( $db ) ? clone ( $db ) : clone ( $GLOBALS [ 'egw' ] -> db );
}
2002-02-18 07:52:33 +01:00
$this -> db_cols = $this -> db_key_cols + $this -> db_data_cols ;
2005-02-27 22:31:10 +01:00
if ( $app )
2003-03-27 18:21:58 +01:00
{
2008-03-13 12:08:54 +01:00
$this -> app = $app ;
2008-04-26 09:49:01 +02:00
2008-03-13 12:08:54 +01:00
if ( ! $no_clone ) $this -> db -> set_app ( $app );
2005-02-27 22:31:10 +01:00
2006-04-19 10:03:28 +02:00
if ( $table ) $this -> setup_table ( $app , $table , $column_prefix );
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
$this -> init ();
2005-10-16 13:45:59 +02:00
if (( int ) $this -> debug >= 4 )
2002-02-18 07:52:33 +01:00
{
echo " <p>so_sql(' $app ',' $table ')</p> \n " ;
_debug_array ( $this );
}
2007-12-04 02:13:53 +01:00
$this -> tz_offset_s = $GLOBALS [ 'egw' ] -> datetime -> tz_offset ;
$this -> now = time () + $this -> tz_offset_s ; // time() is server-time and we need a user-time
2002-02-18 07:52:33 +01:00
}
2008-05-26 10:27:24 +02:00
/**
* php4 constructor
*
* @ deprecated use __construct
*/
2008-05-26 10:32:27 +02:00
function so_sql ( $app = '' , $table = '' , $db = null , $column_prefix = '' , $no_clone = false )
2008-05-26 10:27:24 +02:00
{
2008-05-26 10:32:27 +02:00
self :: __construct ( $app , $table , $db , $column_prefix , $no_clone );
2008-05-26 10:27:24 +02:00
}
2005-02-13 14:03:36 +01:00
/**
2005-02-27 22:31:10 +01:00
* sets up the class for an app and table ( by using the table - definition of $app / setup / tables_current . inc . php
2005-02-13 14:03:36 +01:00
*
2006-04-19 10:03:28 +02:00
* If you need a more complex conversation then just removing the column_prefix , you have to do so in a derifed class ! ! !
*
* @ param string $app app - name $table belongs too
* @ param string $table table - name
* @ param string $colum_prefix = '' column prefix to automatic remove from the column - name , if the column name starts with it
2005-02-13 14:03:36 +01:00
*/
2006-04-19 10:03:28 +02:00
function setup_table ( $app , $table , $colum_prefix = '' )
2002-02-18 07:52:33 +01:00
{
$this -> table_name = $table ;
2006-04-19 10:03:28 +02:00
$this -> table_def = $this -> db -> get_table_definitions ( $app , $table );
if ( ! $this -> table_def || ! is_array ( $this -> table_def [ 'fd' ]))
2005-03-06 22:39:46 +01:00
{
echo " <p>so_sql::setup_table(' $app ',' $table '): No table definitions found !!!<br> \n " . function_backtrace () . " </p> \n " ;
}
2002-02-18 07:52:33 +01:00
$this -> db_key_cols = $this -> db_data_cols = $this -> db_cols = array ();
$this -> autoinc_id = '' ;
2006-04-19 10:03:28 +02:00
$len_prefix = strlen ( $colum_prefix );
foreach ( $this -> table_def [ 'fd' ] as $col => $def )
2002-02-18 07:52:33 +01:00
{
2006-04-19 10:03:28 +02:00
$name = $col ;
if ( $len_prefix && substr ( $name , 0 , $len_prefix ) == $colum_prefix )
2003-03-27 18:21:58 +01:00
{
2006-04-19 10:03:28 +02:00
$name = substr ( $col , $len_prefix );
}
if ( in_array ( $col , $this -> table_def [ 'pk' ]))
{
$this -> db_key_cols [ $col ] = $name ;
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
else
2003-03-27 18:21:58 +01:00
{
2006-04-19 10:03:28 +02:00
$this -> db_data_cols [ $col ] = $name ;
2003-03-27 18:21:58 +01:00
}
2006-04-19 10:03:28 +02:00
$this -> db_cols [ $col ] = $name ;
2002-02-18 07:52:33 +01:00
if ( $def [ 'type' ] == 'auto' )
2003-03-27 18:21:58 +01:00
{
2006-04-19 10:03:28 +02:00
$this -> autoinc_id = $col ;
2003-03-27 18:21:58 +01:00
}
2008-05-28 14:17:06 +02:00
foreach ( $this -> table_def [ 'uc' ] as $k => $uni_index )
2003-03-27 18:21:58 +01:00
{
2008-05-28 14:17:06 +02:00
if ( is_array ( $uni_index ) && in_array ( $name , $uni_index ))
{
$this -> db_uni_cols [ $k ][ $col ] = $name ;
}
elseif ( $name === $uni_index )
{
$this -> db_uni_cols [ $col ] = $name ;
}
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
}
}
2005-02-13 14:03:36 +01:00
/**
* merges in new values from the given new data - array
*
* @ param $new array in form col => new_value with values to set
*/
2003-03-27 18:21:58 +01:00
function data_merge ( $new )
2002-02-18 07:52:33 +01:00
{
2005-10-16 13:45:59 +02:00
if (( int ) $this -> debug >= 4 ) echo " <p>so_sql::data_merge( " . print_r ( $new , true ) . " )</p> \n " ;
2005-04-08 20:30:32 +02:00
2002-02-18 07:52:33 +01:00
if ( ! is_array ( $new ) || ! count ( $new ))
2003-03-27 18:21:58 +01:00
{
2002-02-18 07:52:33 +01:00
return ;
2003-03-27 18:21:58 +01:00
}
foreach ( $this -> db_cols as $db_col => $col )
{
2007-07-05 06:46:49 +02:00
if ( array_key_exists ( $col , $new ))
2003-03-27 18:21:58 +01:00
{
2002-02-18 07:52:33 +01:00
$this -> data [ $col ] = $new [ $col ];
2003-03-27 18:21:58 +01:00
}
}
foreach ( $this -> non_db_cols as $db_col => $col )
{
2007-07-05 06:46:49 +02:00
if ( array_key_exists ( $col , $new ))
2003-03-27 18:21:58 +01:00
{
2002-02-18 07:52:33 +01:00
$this -> data [ $col ] = $new [ $col ];
2003-03-27 18:21:58 +01:00
}
}
2005-10-16 13:45:59 +02:00
if (( int ) $this -> debug >= 4 ) _debug_array ( $this -> data );
2002-02-18 07:52:33 +01:00
}
2005-02-13 14:03:36 +01:00
/**
* changes the data from the db - format to your work - format
*
2007-12-04 02:13:53 +01:00
* It gets called everytime when data is read from the db .
* This default implementation only converts the timestamps mentioned in $this -> timestampfs from server to user time .
* You can reimplement it in a derived class
2005-02-13 14:03:36 +01:00
*
2009-05-03 20:36:38 +02:00
* @ param array $data = null if given works on that array and returns result , else works on internal data - array
2005-02-13 14:03:36 +01:00
*/
function db2data ( $data = null )
2002-02-18 07:52:33 +01:00
{
2005-02-13 14:03:36 +01:00
if ( ! is_array ( $data ))
2003-03-27 18:21:58 +01:00
{
2005-02-13 14:03:36 +01:00
$data = & $this -> data ;
2003-03-27 18:21:58 +01:00
}
2007-12-04 02:13:53 +01:00
if ( $this -> tz_offset_s && $this -> timestamps )
{
foreach ( $this -> timestamps as $name )
{
if ( isset ( $data [ $name ]) && $data [ $name ]) $data [ $name ] += $this -> tz_offset_s ;
}
}
2002-02-18 07:52:33 +01:00
// do the necessare changes here
return $data ;
}
2005-02-13 14:03:36 +01:00
/**
* changes the data from your work - format to the db - format
*
2007-12-04 02:13:53 +01:00
* It gets called everytime when data gets writen into db or on keys for db - searches .
* This default implementation only converts the timestamps mentioned in $this -> timestampfs from user to server time .
* You can reimplement it in a derived class
2005-02-13 14:03:36 +01:00
*
2009-05-03 20:36:38 +02:00
* @ param array $data = null if given works on that array and returns result , else works on internal data - array
2005-02-13 14:03:36 +01:00
*/
function data2db ( $data = null )
2002-02-18 07:52:33 +01:00
{
if ( $intern = ! is_array ( $data ))
2003-03-27 18:21:58 +01:00
{
2005-02-13 14:03:36 +01:00
$data = & $this -> data ;
2003-03-27 18:21:58 +01:00
}
2007-12-04 02:13:53 +01:00
if ( $this -> tz_offset_s && $this -> timestamps )
{
foreach ( $this -> timestamps as $name )
{
if ( isset ( $data [ $name ]) && $data [ $name ]) $data [ $name ] -= $this -> tz_offset_s ;
}
}
2002-02-18 07:52:33 +01:00
// do the necessary changes here
return $data ;
}
2005-02-13 14:03:36 +01:00
/**
* initializes data with the content of key
*
2009-05-03 20:36:38 +02:00
* @ param array $keys = array () array with keys in form internalName => value
2007-01-08 16:57:58 +01:00
* @ return array internal data after init
2005-02-13 14:03:36 +01:00
*/
2003-03-27 18:21:58 +01:00
function init ( $keys = array ())
2002-02-18 07:52:33 +01:00
{
$this -> data = array ();
$this -> db2data ();
$this -> data_merge ( $keys );
2008-04-26 09:49:01 +02:00
2007-01-08 16:57:58 +01:00
return $this -> data ;
2002-02-18 07:52:33 +01:00
}
2005-02-13 14:03:36 +01:00
/**
* reads row matched by key and puts all cols in the data array
*
* @ param array $keys array with keys in form internalName => value , may be a scalar value if only one key
2009-05-03 20:36:38 +02:00
* @ param string | array $extra_cols = '' string or array of strings to be added to the SELECT , eg . " count(*) as num "
* @ param string $join = '' sql to do a join , added as is after the table - name , eg . " , table2 WHERE x=y " or
* @ return array | boolean data if row could be retrived else False
2007-01-08 16:57:58 +01:00
*/
2005-04-10 23:15:33 +02:00
function read ( $keys , $extra_cols = '' , $join = '' )
2002-02-18 07:52:33 +01:00
{
2003-11-03 17:19:48 +01:00
if ( ! is_array ( $keys ))
{
2006-04-19 10:03:28 +02:00
$pk = array_values ( $this -> db_key_cols );
2003-11-03 17:19:48 +01:00
if ( $pk ) $keys = array ( $pk [ 0 ] => $keys );
2008-04-26 09:49:01 +02:00
}
2002-02-18 07:52:33 +01:00
$this -> init ( $keys );
$this -> data2db ();
2005-04-24 19:11:34 +02:00
2005-02-27 22:31:10 +01:00
$query = false ;
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_key_cols as $db_col => $col )
2002-02-18 07:52:33 +01:00
{
if ( $this -> data [ $col ] != '' )
2003-03-27 18:21:58 +01:00
{
2005-02-27 22:31:10 +01:00
$query [ $db_col ] = $this -> data [ $col ];
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
}
if ( ! $query ) // no primary key in keys, lets try the data_cols for a unique key
2003-03-27 18:21:58 +01:00
{
2005-04-24 19:11:34 +02:00
foreach ( $this -> db_uni_cols as $db_col => $col )
2002-02-18 07:52:33 +01:00
{
2008-05-28 14:17:06 +02:00
if ( ! is_array ( $col ) && $this -> data [ $col ] != '' )
2003-03-27 18:21:58 +01:00
{
2005-02-27 22:31:10 +01:00
$query [ $db_col ] = $this -> data [ $col ];
2003-03-27 18:21:58 +01:00
}
2008-05-28 14:17:06 +02:00
elseif ( is_array ( $col ))
{
$q = array ();
foreach ( $col as $db_c => $c )
{
if ( $this -> data [ $col ] == '' )
{
$q = null ;
break ;
}
$q [ $db_c ] = $this -> data [ $c ];
}
if ( $q ) $query += $q ;
}
2002-02-18 07:52:33 +01:00
}
2003-03-27 18:21:58 +01:00
}
2006-07-08 02:38:06 +02:00
if ( ! $query ) // no unique key in keys, lets try everything else
{
foreach ( $this -> db_data_cols as $db_col => $col )
{
if ( $this -> data [ $col ] != '' )
{
$query [ $db_col ] = $this -> data [ $col ];
}
}
}
2002-02-18 07:52:33 +01:00
if ( ! $query ) // keys has no cols
{
$this -> db2data ();
return False ;
}
2007-02-14 08:07:58 +01:00
if ( $join ) // Prefix the columns with the table-name, as they might exist in the join
{
foreach ( $query as $col => $val )
{
2007-04-29 16:25:19 +02:00
if ( is_int ( $col ) || strpos ( $join , $col ) === false ) continue ;
2007-02-14 08:07:58 +01:00
$query [] = $this -> db -> expression ( $this -> table_name , $this -> table_name . '.' , array ( $col => $val ));
unset ( $query [ $col ]);
}
}
2008-03-13 12:08:54 +01:00
foreach ( $this -> db -> select ( $this -> table_name , '*' . ( $extra_cols ? ',' . ( is_array ( $extra_cols ) ? implode ( ',' , $extra_cols ) : $extra_cols ) : '' ),
$query , __LINE__ , __FILE__ , False , '' , $this -> app , 0 , $join ) as $row )
2002-02-18 07:52:33 +01:00
{
2008-03-13 12:08:54 +01:00
$cols = $this -> db_cols ;
if ( $extra_cols ) // extra columns to report
2003-03-27 18:21:58 +01:00
{
2008-03-13 12:08:54 +01:00
foreach ( is_array ( $extra_cols ) ? $extra_cols : array ( $extra_cols ) as $col )
{
if ( FALSE !== stripos ( $col , ' as ' )) $col = preg_replace ( '/^.* as *([a-z0-9_]+) *$/i' , '\\1' , $col );
$cols [ $col ] = $col ;
}
}
foreach ( $cols as $db_col => $col )
{
$this -> data [ $col ] = $row [ $db_col ];
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
$this -> db2data ();
2008-04-26 09:49:01 +02:00
2008-03-13 12:08:54 +01:00
if (( int ) $this -> debug >= 4 )
2005-04-10 23:15:33 +02:00
{
2008-03-13 12:08:54 +01:00
echo " data = \n " ; _debug_array ( $this -> data );
2005-04-10 23:15:33 +02:00
}
2008-03-13 12:08:54 +01:00
return $this -> data ;
2005-04-10 23:15:33 +02:00
}
2008-03-13 12:08:54 +01:00
if ( $this -> autoinc_id )
2005-04-10 23:15:33 +02:00
{
2008-03-13 12:08:54 +01:00
unset ( $this -> data [ $this -> db_key_cols [ $this -> autoinc_id ]]);
2003-03-27 18:21:58 +01:00
}
2008-03-13 12:08:54 +01:00
if (( int ) $this -> debug >= 4 ) echo " nothing found !!!</p> \n " ;
2002-02-18 07:52:33 +01:00
$this -> db2data ();
2008-03-13 12:08:54 +01:00
return False ;
2002-02-18 07:52:33 +01:00
}
2005-02-13 14:03:36 +01:00
/**
* saves the content of data to the db
*
2009-05-03 20:36:38 +02:00
* @ param array $keys = null if given $keys are copied to data before saveing => allows a save as
2008-05-17 08:44:17 +02:00
* @ param string | array $extra_where = null extra where clause , eg . to check an etag , returns true if no affected rows !
* @ return int | boolean 0 on success , or errno != 0 on error , or true if $extra_where is given and no rows affected
2005-02-13 14:03:36 +01:00
*/
2008-04-26 09:49:01 +02:00
function save ( $keys = null , $extra_where = null )
2002-02-18 07:52:33 +01:00
{
2005-02-13 14:03:36 +01:00
if ( is_array ( $keys ) && count ( $keys )) $this -> data_merge ( $keys );
2002-02-18 07:52:33 +01:00
$this -> data2db ();
2005-10-16 13:45:59 +02:00
if (( int ) $this -> debug >= 4 ) { echo " so_sql::save( " . print_r ( $keys , true ) . " ) autoinc_id=' $this->autoinc_id ', data= " ; _debug_array ( $this -> data ); }
2005-04-08 20:30:32 +02:00
2006-04-19 10:03:28 +02:00
if ( $this -> autoinc_id && ! $this -> data [ $this -> db_key_cols [ $this -> autoinc_id ]]) // insert with auto id
2002-02-18 07:52:33 +01:00
{
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_cols as $db_col => $col )
2002-02-18 07:52:33 +01:00
{
2003-03-27 18:21:58 +01:00
if ( ! $this -> autoinc_id || $db_col != $this -> autoinc_id ) // not write auto-inc-id
{
2006-08-29 06:19:38 +02:00
if ( ! array_key_exists ( $col , $this -> data ) && // handling of unset columns in $this->data
2006-04-19 10:03:28 +02:00
( isset ( $this -> table_def [ 'fd' ][ $db_col ][ 'default' ]) || // we have a default value
! isset ( $this -> table_def [ 'fd' ][ $db_col ][ 'nullable' ]) || $this -> table_def [ 'fd' ][ $db_col ][ 'nullable' ])) // column is nullable
{
continue ; // no need to write that (unset) column
}
2005-04-08 20:30:32 +02:00
$data [ $db_col ] = ( string ) $this -> data [ $col ] === '' && $this -> empty_on_write == 'NULL' ? null : $this -> data [ $col ];
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
}
2008-03-13 12:08:54 +01:00
$this -> db -> insert ( $this -> table_name , $data , false , __LINE__ , __FILE__ , $this -> app );
2002-02-18 07:52:33 +01:00
if ( $this -> autoinc_id )
2003-03-27 18:21:58 +01:00
{
2002-02-18 14:51:04 +01:00
$this -> data [ $this -> db_key_cols [ $this -> autoinc_id ]] = $this -> db -> get_last_insert_id ( $this -> table_name , $this -> autoinc_id );
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
}
2006-04-19 10:03:28 +02:00
else // insert in table without auto id or update of existing row, dont write colums unset in $this->data
2002-02-18 07:52:33 +01:00
{
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_data_cols as $db_col => $col )
{
2006-08-29 06:19:38 +02:00
// we need to update columns set to null: after a $this->data[$col]=null:
// - array_key_exits($col,$this->data) === true
// - isset($this->data[$col]) === false
if ( ! array_key_exists ( $col , $this -> data ) && // handling of unset columns in $this->data
2006-04-19 10:03:28 +02:00
( $this -> autoinc_id || // update of table with auto id or
isset ( $this -> table_def [ 'fd' ][ $db_col ][ 'default' ]) || // we have a default value or
! isset ( $this -> table_def [ 'fd' ][ $db_col ][ 'nullable' ]) || $this -> table_def [ 'fd' ][ $db_col ][ 'nullable' ])) // column is nullable
{
continue ; // no need to write that (unset) column
}
2005-04-08 20:30:32 +02:00
$data [ $db_col ] = ( string ) $this -> data [ $col ] === '' && $this -> empty_on_write == 'NULL' ? null : $this -> data [ $col ];
2003-03-27 18:21:58 +01:00
}
2007-09-06 13:56:37 +02:00
// allow to add direct sql updates, eg. "etag=etag+1" with int keys
if ( is_array ( $keys ) && isset ( $keys [ 0 ]))
{
for ( $n = 0 ; isset ( $keys [ $n ]); ++ $n )
{
$data [] = $keys [ $n ];
}
}
2008-04-26 09:49:01 +02:00
$keys = $extra_where ;
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_key_cols as $db_col => $col )
{
2005-02-27 22:31:10 +01:00
$keys [ $db_col ] = $this -> data [ $col ];
2003-03-27 18:21:58 +01:00
}
2005-05-21 20:17:21 +02:00
if ( ! $data && ! $this -> autoinc_id ) // happens if all columns are in the primary key
{
$data = $keys ;
$keys = False ;
}
2008-05-17 08:44:17 +02:00
if ( $this -> autoinc_id )
{
$this -> db -> update ( $this -> table_name , $data , $keys , __LINE__ , __FILE__ , $this -> app );
if (( $nothing_affected = ! $this -> db -> Errno && ! $this -> db -> affected_rows ()) && $extra_where )
{
return true ; // extra_where not met, eg. etag wrong
}
}
2008-04-27 22:05:04 +02:00
// always try an insert if we have no autoinc_id, as we dont know if the data exists
2008-05-17 08:44:17 +02:00
if ( ! $this -> autoinc_id || $nothing_affected )
2005-04-08 20:30:32 +02:00
{
2008-03-13 12:08:54 +01:00
$this -> db -> insert ( $this -> table_name , $data , $keys , __LINE__ , __FILE__ , $this -> app );
2005-04-08 20:30:32 +02:00
}
2003-03-27 18:21:58 +01:00
}
2002-02-18 07:52:33 +01:00
$this -> db2data ();
2008-05-17 08:44:17 +02:00
return $this -> db -> Errno ;
2002-02-18 07:52:33 +01:00
}
2007-07-05 06:46:49 +02:00
/**
* Update only the given fields , if the primary key is not given , it will be taken from $this -> data
2008-04-26 09:49:01 +02:00
*
2007-07-05 06:46:49 +02:00
* @ param array $fields
* @ param boolean $merge = true if true $fields will be merged with $this -> data ( after update ! ), otherwise $this -> data will be just $fields
2008-07-02 17:25:54 +02:00
* @ return int | boolean 0 on success , or errno != 0 on error , or true if $extra_where is given and no rows affected
2007-07-05 06:46:49 +02:00
*/
function update ( $fields , $merge = true )
{
2008-07-02 17:25:54 +02:00
if ( $merge ) $this -> data_merge ( $fields );
$fields = $this -> data2db ( $fields );
2007-07-05 06:46:49 +02:00
2008-07-02 17:25:54 +02:00
// extract the keys from $fields or - if not set there - from $this->data
$keys = array ();
foreach ( $this -> db_key_cols as $col => $name )
{
$keys [ $col ] = isset ( $fields [ $name ]) ? $fields [ $name ] : $this -> data [ $name ];
unset ( $fields [ $name ]);
}
// extract the data from $fields
$data = array ();
foreach ( $this -> db_data_cols as $col => $name )
2007-07-05 06:46:49 +02:00
{
2008-07-02 17:25:54 +02:00
if ( array_key_exists ( $name , $fields ))
2007-07-05 06:46:49 +02:00
{
2008-07-02 17:25:54 +02:00
$data [ $col ] = $fields [ $name ];
unset ( $fields [ $name ]);
2007-07-05 06:46:49 +02:00
}
}
2008-07-02 17:25:54 +02:00
// add direct sql like 'etag=etag+1' (it has integer keys)
foreach ( $fields as $key => $value )
{
if ( is_int ( $key ))
{
$data [] = $value ;
}
}
if ( ! $data )
{
return 0 ; // nothing to update
}
if ( ! $this -> db -> update ( $this -> table_name , $data , $keys , __LINE__ , __FILE__ , $this -> app ))
2007-07-05 06:46:49 +02:00
{
2008-07-02 17:25:54 +02:00
return $this -> db -> Errno ;
2007-07-05 06:46:49 +02:00
}
2008-07-02 17:25:54 +02:00
return 0 ;
2007-07-05 06:46:49 +02:00
}
2008-04-26 09:49:01 +02:00
2005-02-13 14:03:36 +01:00
/**
* deletes row representing keys in internal data or the supplied $keys if != null
*
2009-05-03 20:36:38 +02:00
* @ param array $keys = null if given array with col => value pairs to characterise the rows to delete
2009-01-17 04:36:58 +01:00
* @ param boolean $only_return_query = false return $query of delete call to db object , but not run it ( used by so_sql_cf ! )
2005-04-15 00:09:40 +02:00
* @ return int affected rows , should be 1 if ok , 0 if an error
*/
2009-01-17 04:36:58 +01:00
function delete ( $keys = null , $only_return_query = false )
2002-02-18 07:52:33 +01:00
{
2008-06-04 07:26:52 +02:00
if ( $this -> autoinc_id && $keys && ! is_array ( $keys ))
{
$keys = array ( $this -> autoinc_id => $keys );
}
2002-02-18 07:52:33 +01:00
if ( ! is_array ( $keys ) || ! count ( $keys )) // use internal data
{
$data = $this -> data ;
$keys = $this -> db_key_cols ;
}
else // data and keys are supplied in $keys
{
$data = $keys ; $keys = array ();
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_cols as $db_col => $col )
{
2002-02-18 07:52:33 +01:00
if ( isset ( $data [ $col ]))
2003-03-27 18:21:58 +01:00
{
2002-02-18 07:52:33 +01:00
$keys [ $db_col ] = $col ;
2003-03-27 18:21:58 +01:00
}
}
2002-02-18 07:52:33 +01:00
}
$data = $this -> data2db ( $data );
2003-03-27 18:21:58 +01:00
foreach ( $keys as $db_col => $col )
{
2005-02-27 22:31:10 +01:00
$query [ $db_col ] = $data [ $col ];
2003-03-27 18:21:58 +01:00
}
2009-01-17 04:36:58 +01:00
if ( $only_return_query ) return $query ;
2009-03-11 13:14:15 +01:00
2008-03-13 12:08:54 +01:00
$this -> db -> delete ( $this -> table_name , $query , __LINE__ , __FILE__ , $this -> app );
2002-02-18 07:52:33 +01:00
return $this -> db -> affected_rows ();
}
2005-02-13 14:03:36 +01:00
/**
* searches db for rows matching searchcriteria
*
* '*' and '?' are replaced with sql - wildcards '%' and '_'
*
2006-04-05 17:22:50 +02:00
* For a union - query you call search for each query with $start == 'UNION' and one more with only $order_by and $start set to run the union - query .
*
2009-05-03 20:36:38 +02:00
* @ param array | string $criteria array of key and data cols , OR a SQL query ( content for WHERE ), fully quoted ( ! )
* @ param boolean | string | array $only_keys = true True returns only keys , False returns all cols . or
2006-04-24 22:48:18 +02:00
* comma seperated list or array of columns to return
2005-04-24 19:11:34 +02:00
* @ param string $order_by = '' fieldnames + { ASC | DESC } separated by colons ',' , can also contain a GROUP BY ( if it contains ORDER BY )
2009-05-03 20:36:38 +02:00
* @ param string | array $extra_cols = '' string or array of strings to be added to the SELECT , eg . " count(*) as num "
2005-04-24 19:11:34 +02:00
* @ param string $wildcard = '' appended befor and after each criteria
* @ param boolean $empty = false False = empty criteria are ignored in query , True = empty have to be empty in row
* @ param string $op = 'AND' defaults to 'AND' , can be set to 'OR' too , then criteria 's are OR' ed together
2006-04-05 17:22:50 +02:00
* @ param mixed $start = false if != false , return only maxmatch rows begining with start , or array ( $start , $num ), or 'UNION' for a part of a union query
2005-04-24 19:11:34 +02:00
* @ param array $filter = null if set ( != null ) col - data pairs , to be and - ed ( ! ) into the query without wildcards
2006-04-24 22:48:18 +02:00
* @ param string $join = '' sql to do a join , added as is after the table - name , eg . " JOIN table2 ON x=y " or
* " LEFT JOIN table2 ON (x=y AND z=o) " , Note : there ' s no quoting done on $join , you are responsible for it !!!
2005-05-19 15:15:19 +02:00
* @ param boolean $need_full_no_count = false If true an unlimited query is run to determine the total number of rows , default false
2009-05-03 20:36:38 +02:00
* @ return array | NULL array of matching rows ( the row is an array of the cols ) or NULL
2005-02-13 14:03:36 +01:00
*/
2005-05-19 15:15:19 +02:00
function & search ( $criteria , $only_keys = True , $order_by = '' , $extra_cols = '' , $wildcard = '' , $empty = False , $op = 'AND' , $start = false , $filter = null , $join = '' , $need_full_no_count = false )
2002-02-18 07:52:33 +01:00
{
2006-04-24 22:48:18 +02:00
if (( int ) $this -> debug >= 4 ) echo " <p>so_sql::search( " . print_r ( $criteria , true ) . " ,' $only_keys ',' $order_by ', " . print_r ( $extra_cols , true ) . " ,' $wildcard ',' $empty ',' $op ',' $start ', " . print_r ( $filter , true ) . " ,' $join ')</p> \n " ;
2005-04-27 22:47:34 +02:00
2003-04-16 16:32:15 +02:00
if ( ! is_array ( $criteria ))
{
2005-02-27 22:31:10 +01:00
$query = $criteria ;
2003-04-16 16:32:15 +02:00
}
else
{
$criteria = $this -> data2db ( $criteria );
2005-05-19 15:15:19 +02:00
foreach ( $criteria as $col => $val )
{
if ( is_int ( $col ))
{
$query [] = $val ;
}
elseif ( $empty || $val != '' )
2003-04-16 16:32:15 +02:00
{
2005-05-19 15:15:19 +02:00
if ( ! ( $db_col = array_search ( $col , $this -> db_cols )))
{
$db_col = $col ;
}
2008-05-26 10:27:24 +02:00
if ( $wildcard || $criteria [ $col ][ 0 ] == '!' ||
2006-12-07 20:05:40 +01:00
is_string ( $criteria [ $col ]) && ( strpos ( $criteria [ $col ], '*' ) !== false || strpos ( $criteria [ $col ], '?' ) !== false ))
2005-04-08 20:30:32 +02:00
{
2006-12-17 09:44:05 +01:00
$cmp_op = ' ' . $this -> db -> capabilities [ 'case_insensitive_like' ] . ' ' ;
2008-06-17 09:28:35 +02:00
$negate = false ;
2008-05-26 10:27:24 +02:00
if ( $criteria [ $col ][ 0 ] == '!' )
2005-11-01 11:13:28 +01:00
{
2006-12-17 09:44:05 +01:00
$cmp_op = ' NOT' . $cmp_op ;
2008-06-19 18:07:57 +02:00
$criteria [ $col ] = substr ( $criteria [ $col ], 1 );
2008-06-17 09:28:35 +02:00
$negate = true ;
2005-11-01 11:13:28 +01:00
}
2008-06-26 18:08:47 +02:00
foreach ( explode ( ' ' , $criteria [ $col ]) as $crit )
{
$query [] = ( $negate ? ' (' . $db_col . ' IS NULL OR ' : '' ) . $db_col . $cmp_op . $this -> db -> quote ( $wildcard . str_replace ( array ( '%' , '_' , '*' , '?' ), array ( '\\%' , '\\_' , '%' , '_' ), $crit ) . $wildcard ) . ( $negate ? ') ' : '' );
}
2005-04-08 20:30:32 +02:00
}
2006-12-07 13:46:46 +01:00
elseif ( strpos ( $db_col , '.' ) !== false ) // we have a table-name specified
2005-05-19 15:15:19 +02:00
{
list ( $table , $only_col ) = explode ( '.' , $db_col );
2008-04-26 09:49:01 +02:00
2006-04-23 16:42:41 +02:00
$table_def = $this -> db -> get_table_definitions ( true , $table );
2008-03-13 12:08:54 +01:00
if ( is_array ( $val ) && count ( $val ) > 1 )
{
array_walk ( $val , array ( $this -> db , 'quote' ), $table_def [ 'fd' ][ $only_col ][ 'type' ]);
$query [] = $sql = $db_col . ' IN (' . implode ( ',' , $val ) . ')' ;
}
else
{
$query [] = $db_col . '=' . $this -> db -> quote ( is_array ( $val ) ? array_shift ( $val ) : $val , $table_def [ 'fd' ][ $only_col ][ 'type' ]);
}
2005-05-19 15:15:19 +02:00
}
2005-04-08 20:30:32 +02:00
else
{
$query [ $db_col ] = $criteria [ $col ];
}
2003-04-16 16:32:15 +02:00
}
2003-03-27 18:21:58 +01:00
}
2005-04-08 20:30:32 +02:00
if ( is_array ( $query ) && $op != 'AND' ) $query = $this -> db -> column_data_implode ( ' ' . $op . ' ' , $query );
2002-02-18 07:52:33 +01:00
}
2005-02-27 22:31:10 +01:00
if ( is_array ( $filter ))
{
$db_filter = array ();
2005-03-05 15:54:14 +01:00
$data2db_filter = $this -> data2db ( $filter );
if ( ! is_array ( $data2db_filter )) {
echo function_backtrace () . " <br/> \n " ;
echo " filter= " ; _debug_array ( $filter );
echo " data2db(filter)= " ; _debug_array ( $data2db_filter );
2008-04-26 09:49:01 +02:00
}
2005-03-29 19:06:50 +02:00
foreach ( $data2db_filter as $col => $val )
2005-02-27 22:31:10 +01:00
{
2005-04-19 15:54:55 +02:00
if ( $val !== '' )
{
2005-04-22 15:49:36 +02:00
// check if a db-internal name conversation necessary
2008-04-26 09:49:01 +02:00
if ( ! is_int ( $col ) && ( $c = array_search ( $col , $this -> db_cols )))
2005-04-22 15:49:36 +02:00
{
$col = $c ;
}
2006-06-17 20:30:38 +02:00
if ( is_int ( $col ))
{
$db_filter [] = $val ;
}
elseif ( $val === " !'' " )
2006-04-24 22:48:18 +02:00
{
$db_filter [] = $col . " != '' " ;
}
else
{
$db_filter [ $col ] = $val ;
}
2005-04-19 15:54:55 +02:00
}
2005-02-27 22:31:10 +01:00
}
2008-04-26 09:49:01 +02:00
if ( $query )
2005-04-08 20:30:32 +02:00
{
if ( $op != 'AND' )
{
$db_filter [] = '(' . $this -> db -> column_data_implode ( ' ' . $op . ' ' , $query ) . ')' ;
}
2008-04-26 09:49:01 +02:00
else
2005-04-08 20:30:32 +02:00
{
$db_filter = array_merge ( $db_filter , $query );
}
}
2005-02-27 22:31:10 +01:00
$query = $db_filter ;
}
2006-03-27 00:09:02 +02:00
if (( int ) $this -> debug >= 4 )
{
echo " <p>so_sql::search(,only_keys= $only_keys ,order_by=' $order_by ',wildcard=' $wildcard ',empty= $empty , $op ,start=' $start ', " . print_r ( $filter , true ) . " ) query= " . print_r ( $query , true ) . " , total=' $this->total '</p> \n " ;
echo " <br>criteria = " ; _debug_array ( $criteria );
}
2006-04-24 22:48:18 +02:00
if ( $only_keys === true )
{
$colums = implode ( ',' , array_keys ( $this -> db_key_cols ));
}
elseif ( is_array ( $only_keys ))
{
$colums = array ();
foreach ( $only_keys as $key => $col )
{
$colums [] = ( $db_col = array_search ( $col , $this -> db_cols )) ? $db_col : $col ;
}
$colums = implode ( ',' , $colums );
}
elseif ( ! $only_keys )
{
$colums = '*' ;
}
else
{
$colums = $only_keys ;
}
2006-05-17 05:02:47 +02:00
if ( $extra_cols ) $colums .= ( $colums ? ',' : '' ) . ( is_array ( $extra_cols ) ? implode ( ',' , $extra_cols ) : $extra_cols );
2006-03-27 00:09:02 +02:00
2005-04-24 19:11:34 +02:00
$num_rows = 0 ; // as spec. in max_matches in the user-prefs
if ( is_array ( $start )) list ( $start , $num_rows ) = $start ;
2008-04-26 09:49:01 +02:00
2006-12-07 13:46:46 +01:00
if ( $order_by && stripos ( $order_by , 'ORDER BY' ) === false && stripos ( $order_by , 'GROUP BY' ) === false )
2006-03-27 00:09:02 +02:00
{
$order_by = 'ORDER BY ' . $order_by ;
}
static $union = array ();
static $union_cols = array ();
if ( $start === 'UNION' || $union )
{
if ( $start === 'UNION' )
2005-05-19 15:15:19 +02:00
{
2006-04-05 17:22:50 +02:00
$union [] = array (
'table' => $this -> table_name ,
'cols' => $colums ,
'where' => $query ,
'append' => $order_by ,
'join' => $join ,
);
2006-03-27 00:09:02 +02:00
if ( ! $union_cols ) // union used the colum-names of the first query
{
$union_cols = $this -> _get_columns ( $only_keys , $extra_cols );
}
return true ; // waiting for further calls, before running the union-query
2005-05-19 15:15:19 +02:00
}
2006-03-27 00:09:02 +02:00
// running the union query now
2008-10-07 10:17:09 +02:00
if ( $start !== false ) // need to get the total too, saved in $this->total
2005-04-27 22:47:34 +02:00
{
2006-03-27 00:09:02 +02:00
if ( $this -> db -> Type == 'mysql' && $this -> db -> ServerInfo [ 'version' ] >= 4.0 )
{
$union [ 0 ][ 'cols' ] = ( $mysql_calc_rows = 'SQL_CALC_FOUND_ROWS ' ) . $union [ 0 ][ 'cols' ];
}
else // cant do a count, have to run the query without limit
{
2008-03-13 12:08:54 +01:00
$this -> total = $this -> db -> union ( $union , __LINE__ , __FILE__ ) -> NumRows ();
2006-03-27 00:09:02 +02:00
}
2005-04-27 22:47:34 +02:00
}
2008-03-13 12:08:54 +01:00
$rs = $this -> db -> union ( $union , __LINE__ , __FILE__ , $order_by , $start , $num_rows );
2006-03-27 00:09:02 +02:00
$cols = $union_cols ;
$union = $union_cols = array ();
}
else // no UNION
{
2008-10-07 10:17:09 +02:00
if ( $start !== false ) // need to get the total too, saved in $this->total
2005-04-27 22:47:34 +02:00
{
2006-03-27 00:09:02 +02:00
if ( $this -> db -> Type == 'mysql' && $this -> db -> ServerInfo [ 'version' ] >= 4.0 )
{
$mysql_calc_rows = 'SQL_CALC_FOUND_ROWS ' ;
}
2006-12-07 13:46:46 +01:00
elseif ( ! $need_full_no_count && ( ! $join || stripos ( $join , 'LEFT JOIN' ) !== false ))
2006-03-27 00:09:02 +02:00
{
2009-06-08 18:21:14 +02:00
$this -> total = $this -> db -> select ( $this -> table_name , 'COUNT(*)' , $query , __LINE__ , __FILE__ , false , '' , $this -> app , 0 , $join ) -> fetchColumn ();
2006-03-27 00:09:02 +02:00
}
else // cant do a count, have to run the query without limit
{
2008-03-13 12:08:54 +01:00
$this -> total = $this -> db -> select ( $this -> table_name , $colums , $query , __LINE__ , __FILE__ , false , $order_by , false , 0 , $join ) -> NumRows ();
2006-03-27 00:09:02 +02:00
}
2005-04-27 22:47:34 +02:00
}
2008-03-13 12:08:54 +01:00
$rs = $this -> db -> select ( $this -> table_name , $mysql_calc_rows . $colums , $query , __LINE__ , __FILE__ ,
$start , $order_by , $this -> app , $num_rows , $join );
2002-02-18 07:52:33 +01:00
2006-03-27 00:09:02 +02:00
$cols = $this -> _get_columns ( $only_keys , $extra_cols );
}
2006-04-24 22:48:18 +02:00
if (( int ) $this -> debug >= 4 ) echo " <p>sql=' { $this -> db -> Query_ID -> sql } '</p> \n " ;
2005-05-19 15:15:19 +02:00
if ( $mysql_calc_rows )
{
2009-06-08 18:21:14 +02:00
$this -> total = $this -> db -> query ( 'SELECT FOUND_ROWS()' ) -> fetchColumn ();
2005-05-19 15:15:19 +02:00
}
2006-03-27 00:09:02 +02:00
$arr = array ();
2008-03-13 12:08:54 +01:00
if ( $rs ) foreach ( $rs as $row )
2002-02-18 07:52:33 +01:00
{
2006-03-27 00:09:02 +02:00
$data = array ();
foreach ( $cols as $db_col => $col )
{
$data [ $col ] = $row [ $db_col ];
}
$arr [] = $this -> db2data ( $data );
2008-03-13 12:08:54 +01:00
$n ++ ;
2002-02-18 07:52:33 +01:00
}
2009-05-03 20:36:38 +02:00
return $n ? $arr : null ;
2006-03-27 00:09:02 +02:00
}
/**
* extract the requested columns from $only_keys and $extra_cols param of a search
*
2008-04-26 09:49:01 +02:00
* @ internal
2009-05-03 20:36:38 +02:00
* @ param boolean | string $only_keys = true True returns only keys , False returns all cols . comma seperated list of keys to return
* @ param string | array $extra_cols = '' string or array of strings to be added to the SELECT , eg . " count(*) as num "
2006-03-27 00:09:02 +02:00
* @ return array with columns as db - name => internal - name pairs
2008-04-26 09:49:01 +02:00
*/
2006-03-27 00:09:02 +02:00
function _get_columns ( $only_keys , $extra_cols )
{
2006-04-24 22:48:18 +02:00
//echo "_get_columns() only_keys="; _debug_array($only_keys); echo "extra_cols="; _debug_array($extra_cols);
2005-04-15 00:09:40 +02:00
if ( $only_keys === true ) // only primary key
2005-04-08 20:30:32 +02:00
{
$cols = $this -> db_key_cols ;
}
2005-04-24 19:11:34 +02:00
else
2005-04-08 20:30:32 +02:00
{
2005-04-24 19:11:34 +02:00
$cols = array ();
2006-04-24 22:48:18 +02:00
foreach ( is_array ( $only_keys ) ? $only_keys : explode ( ',' , str_replace ( array ( 'DISTINCT ' , 'distinct ' ), '' , $only_keys )) as $col )
2005-04-08 20:30:32 +02:00
{
2005-04-24 19:11:34 +02:00
if ( ! $col || $col == '*' || $col == $this -> table_name . '.*' ) // all columns
{
$cols = array_merge ( $cols , $this -> db_cols );
}
else // only the specified columns
{
2006-12-07 13:46:46 +01:00
if ( stripos ( $col , 'as' ) !== false ) $col = preg_replace ( '/^.*as +([a-z0-9_]+) *$/i' , '\\1' , $col );
2006-04-24 22:48:18 +02:00
if (( $db_col = array_search ( $col , $this -> db_cols )) !== false )
{
$cols [ $db_col ] = $col ;
}
else
{
$cols [ $col ] = isset ( $this -> db_cols [ $col ]) ? $this -> db_cols [ $col ] : $col ;
}
2005-04-24 19:11:34 +02:00
}
2005-04-08 20:30:32 +02:00
}
}
if ( $extra_cols ) // extra columns to report
2005-03-05 15:54:14 +01:00
{
2005-04-20 19:27:48 +02:00
foreach ( is_array ( $extra_cols ) ? $extra_cols : explode ( ',' , $extra_cols ) as $col )
2005-03-05 15:54:14 +01:00
{
2006-12-07 13:46:46 +01:00
if ( stripos ( $col , 'as ' ) !== false ) $col = preg_replace ( '/^.*as +([a-z0-9_]+) *$/i' , '\\1' , $col );
2006-04-24 22:48:18 +02:00
if (( $db_col = array_search ( $col , $this -> db_cols )) !== false )
{
$cols [ $db_col ] = $col ;
}
else
{
$cols [ $col ] = isset ( $this -> db_cols [ $col ]) ? $this -> db_cols [ $col ] : $col ;
}
2005-03-05 15:54:14 +01:00
}
}
2006-03-27 00:09:02 +02:00
return $cols ;
2002-02-18 07:52:33 +01:00
}
2005-02-27 22:31:10 +01:00
/**
* query rows for the nextmatch widget
*
* @ param array $query with keys 'start' , 'search' , 'order' , 'sort' , 'col_filter'
* For other keys like 'filter' , 'cat_id' you have to reimplement this method in a derived class .
* @ param array & $rows returned rows / competitions
* @ param array & $readonlys eg . to disable buttons based on acl , not use here , maybe in a derived class
2008-04-26 09:49:01 +02:00
* @ param string $join = '' sql to do a join , added as is after the table - name , eg . " , table2 WHERE x=y " or
2005-04-27 22:47:34 +02:00
* " LEFT JOIN table2 ON (x=y) " , Note : there ' s no quoting done on $join !
2005-05-19 15:15:19 +02:00
* @ param boolean $need_full_no_count = false If true an unlimited query is run to determine the total number of rows , default false
2008-03-13 12:08:54 +01:00
* @ param mixed $only_keys = false , see search
2009-05-03 20:36:38 +02:00
* @ param string | array $extra_cols = array ()
2005-05-19 15:15:19 +02:00
* @ return int total number of rows
2005-02-27 22:31:10 +01:00
*/
2009-03-11 13:14:15 +01:00
function get_rows ( $query , & $rows , & $readonlys , $join = '' , $need_full_no_count = false , $only_keys = false , $extra_cols = array ())
2005-02-27 22:31:10 +01:00
{
2005-10-16 13:45:59 +02:00
if (( int ) $this -> debug >= 4 )
2005-02-27 22:31:10 +01:00
{
echo " <p>so_sql::get_rows( " . print_r ( $query , true ) . " ,,)</p> \n " ;
}
$criteria = array ();
if ( $query [ 'search' ])
{
foreach ( $this -> db_cols as $col ) // we search all cols
{
$criteria [ $col ] = $query [ 'search' ];
}
}
2009-03-11 13:14:15 +01:00
$rows = $this -> search ( $criteria , $only_keys , $query [ 'order' ] ? $query [ 'order' ] . ' ' . $query [ 'sort' ] : '' , $extra_cols ,
'%' , false , 'OR' , $query [ 'num_rows' ] ? array (( int ) $query [ 'start' ], $query [ 'num_rows' ]) : ( int ) $query [ 'start' ],
2007-10-07 15:29:24 +02:00
$query [ 'col_filter' ], $join , $need_full_no_count );
2008-04-26 09:49:01 +02:00
2007-11-27 22:24:50 +01:00
if ( ! $rows ) $rows = array (); // otherwise false returned from search would be returned as array(false)
2005-02-27 22:31:10 +01:00
return $this -> total ;
}
2008-04-26 09:49:01 +02:00
2005-02-13 14:03:36 +01:00
/**
2008-05-28 14:17:06 +02:00
* Check if values for unique keys and the primary keys are unique are unique
2005-02-13 14:03:36 +01:00
*
2009-05-03 20:36:38 +02:00
* @ param array $data = null data - set to check , defaults to $this -> data
2005-02-13 14:03:36 +01:00
* @ return int 0 : all keys are unique , 1 : first key not unique , 2 : ...
*/
function not_unique ( $data = null )
2002-02-18 07:52:33 +01:00
{
if ( ! is_array ( $data ))
2003-03-27 18:21:58 +01:00
{
2002-02-18 07:52:33 +01:00
$data = $this -> data ;
2003-03-27 18:21:58 +01:00
}
$n = 1 ;
2008-05-30 10:20:06 +02:00
$uni_keys = $this -> db_uni_cols ;
// add the primary key, only if it's NOT an auto id
if ( ! $this -> autoinc_id )
{
$uni_keys [] = $this -> db_key_cols ;
}
foreach ( $uni_keys as $db_col => $col )
2002-02-18 07:52:33 +01:00
{
2008-05-28 14:17:06 +02:00
if ( is_array ( $col ))
{
$query = array ();
foreach ( $col as $db_c => $c )
{
$query [ $db_c ] = $data [ $c ];
}
}
else
{
$query = array ( $db_col => $data [ $col ]);
}
2008-09-22 18:00:45 +02:00
foreach ( $this -> db -> select ( $this -> table_name , $this -> db_key_cols , $query , __LINE__ , __FILE__ , false , '' , $this -> app ) as $other )
2002-02-18 07:52:33 +01:00
{
2003-03-27 18:21:58 +01:00
foreach ( $this -> db_key_cols as $db_key_col => $key_col )
2002-02-18 07:52:33 +01:00
{
2005-04-08 20:30:32 +02:00
if ( $data [ $key_col ] != $other [ $key_col ])
2003-03-27 18:21:58 +01:00
{
2008-06-04 07:26:52 +02:00
if (( int ) $this -> debug >= 4 )
2002-02-18 07:52:33 +01:00
{
2008-05-30 10:20:06 +02:00
echo " <p>not_unique in " . array2string ( $col ) . " as for ' $key_col ': ' ${ data[$key_col] } ' != ' ${ other[$key_col] } '</p> \n " ;
2002-02-18 07:52:33 +01:00
}
return $n ; // different entry => $n not unique
}
}
}
2003-03-27 18:21:58 +01:00
++ $n ;
2002-02-18 07:52:33 +01:00
}
return 0 ;
}
2008-04-26 09:49:01 +02:00
2005-05-10 16:44:34 +02:00
/**
2005-05-21 20:17:21 +02:00
* Query DB for a list / array with one colum as key and an other one ( s ) as value , eg . id => title pairs
2005-05-10 16:44:34 +02:00
*
* We do some caching as these kind of function is usualy called multiple times , eg . for option - lists .
*
2005-05-21 20:17:21 +02:00
* @ param string $value_col array of column - names for the values of the array , can also be an expression aliased with AS ,
* if more then one column given , an array with keys identical to the given ones is returned and not just the value of the column
* @ param string $key_col = '' column - name for the keys , default '' = same as ( first ) $value_col : returns a distinct list
2005-05-10 16:44:34 +02:00
* @ param array $filter = array () to filter the entries
2005-05-21 20:17:21 +02:00
* @ param string $order = '' order , default '' = same as ( first ) $value_col
* @ return array with key_col => value_col pairs or array if more then one value_col given ( keys as in value_col )
2005-05-10 16:44:34 +02:00
*/
2005-05-19 15:15:19 +02:00
function query_list ( $value_col , $key_col = '' , $filter = array (), $order = '' )
2005-05-10 16:44:34 +02:00
{
static $cache = array ();
2008-04-26 09:49:01 +02:00
2005-05-21 20:17:21 +02:00
$cache_key = serialize ( $value_col ) . '-' . $key_col . '-' . serialize ( $filter ) . '-' . $order ;
2008-04-26 09:49:01 +02:00
2005-05-10 16:44:34 +02:00
if ( isset ( $cache [ $cache_key ]))
{
return $cache [ $cache_key ];
}
2005-05-21 20:17:21 +02:00
if ( ! is_array ( $value_col )) $value_col = array ( $value_col );
2008-04-26 09:49:01 +02:00
2005-05-21 20:17:21 +02:00
$cols = array ();
2006-04-23 16:42:41 +02:00
foreach ( $value_col as $key => $col )
2005-05-19 15:15:19 +02:00
{
2005-05-21 20:17:21 +02:00
$cols [ $key ] = preg_match ( '/AS ([a-z_0-9]+)$/i' , $col , $matches ) ? $matches [ 1 ] : $col ;
2008-04-26 09:49:01 +02:00
}
2005-05-21 20:17:21 +02:00
if ( ! $order ) $order = current ( $cols );
2005-05-19 15:15:19 +02:00
2005-05-21 20:17:21 +02:00
if (( $search =& $this -> search ( array (),( $key_col ? $key_col . ',' : 'DISTINCT ' ) . implode ( ',' , $value_col ), $order , '' , '' , false , 'AND' , false , $filter )))
2005-05-10 16:44:34 +02:00
{
2005-05-19 15:15:19 +02:00
if ( preg_match ( '/AS ([a-z_0-9]+)$/i' , $key_col , $matches ))
2005-05-10 16:44:34 +02:00
{
2005-05-19 15:15:19 +02:00
$key_col = $matches [ 1 ];
2005-05-10 16:44:34 +02:00
}
2005-05-21 20:17:21 +02:00
elseif ( ! $key_col )
{
$key_col = current ( $cols );
}
2005-05-10 16:44:34 +02:00
foreach ( $search as $row )
{
2005-05-21 20:17:21 +02:00
if ( count ( $cols ) > 1 )
{
$data = array ();
foreach ( $cols as $key => $col )
{
$data [ $key ] = $row [ $col ];
}
}
else
{
$data = $row [ current ( $cols )];
}
$ret [ $row [ $key_col ]] = $data ;
2005-05-10 16:44:34 +02:00
}
}
return $cache [ $cache_key ] =& $ret ;
}
2009-05-13 11:58:21 +02:00
/**
* Get comments for all columns or a specific one
*
* @ param $column = null name of column or null for all ( default )
* @ return array | string array with internal - name => comment pairs , or string with comment , if $column given
*/
public function get_comments ( $column = null )
{
static $comments ;
if ( is_null ( $comments ))
{
foreach ( $this -> db_cols as $db_col => $col )
{
$comments [ $col ] = $this -> table_def [ 'fd' ][ $db_col ][ 'comment' ];
}
}
return is_null ( $column ) ? $comments : $comments [ $column ];
}
2005-02-13 14:03:36 +01:00
}