2016-10-06 15:57:01 +00:00
< ? php
2021-01-26 18:41:21 +00:00
2016-10-06 15:57:01 +00:00
/**
* @ package Contenido Backend classes
2019-07-03 11:58:28 +00:00
* @ version $Id $
2016-10-06 15:57:01 +00:00
* @ author Timo A . Hummel
* @ author Murat Purc < murat @ purc . de >
* @ copyright four for business AG < www . 4 fb . de >
* @ license http :// www . contenido . org / license / LIZENZ . txt
* @ link http :// www . 4 fb . de
* @ link http :// www . contenido . org
* @ since file available since contenido release <= 4.6
*/
if ( ! defined ( 'CON_FRAMEWORK' )) {
die ( 'Illegal call' );
}
global $cfg ;
// Try to load GenericDB database driver
2021-01-26 18:41:21 +00:00
$driver_filename = $cfg [ 'path' ][ 'contenido' ] . $cfg [ 'path' ][ 'classes' ] . 'drivers/' . $cfg [ 'sql' ][ 'gdb_driver' ] . '/class.gdb.' . $cfg [ 'sql' ][ 'gdb_driver' ] . '.php' ;
2016-10-06 15:57:01 +00:00
if ( file_exists ( $driver_filename )) {
include_once ( $driver_filename );
}
2016-10-08 13:39:50 +00:00
// load all genericdb classes
cInclude ( " classes " , " genericdb/class.item.base.abstract.php " );
cInclude ( " classes " , " genericdb/class.item.cache.php " );
2016-10-06 15:57:01 +00:00
/**
* Class Contenido_ItemException .
* @ author Murat Purc < murat @ purc . de >
* @ version 0.1
* @ copyright four for business AG < www . 4 fb . de >
*/
2021-01-26 18:41:21 +00:00
class Contenido_ItemException extends Exception {
}
2016-10-06 15:57:01 +00:00
2021-01-26 18:41:21 +00:00
/**
2016-10-06 15:57:01 +00:00
* Class ItemCollection
* Abstract class for database based item collections .
*
* @ author Timo A . Hummel < Timo . Hummel @ 4 fb . de >
* @ author Murat Purc < murat @ purc . de >
* @ version 0.2
* @ copyright four for business 2003
*/
2021-01-26 18:41:21 +00:00
abstract class ItemCollection extends cItemBaseAbstract {
2016-10-06 15:57:01 +00:00
/**
* Storage of all result items
* @ var string Contains all result items
*/
protected $objects ;
/**
* GenericDB driver object
* @ var gdbDriver
*/
protected $_driver ;
/**
* List of instances of ItemCollection implementations
* @ var array
*/
protected $_collectionCache = array ();
/**
* @ var string Single item class
*/
protected $_itemClass ;
2021-01-26 18:41:21 +00:00
2016-10-06 15:57:01 +00:00
/**
* @ var Item object of single item class
*/
protected $_itemClassInstance = NULL ;
/**
* @ var object Iterator object for the next () method
*/
protected $_iteratorItem ;
/**
* @ var array Reverse join partners for this data object
*/
protected $_JoinPartners ;
/**
* @ var array Forward join partners for this data object
*/
protected $_forwardJoinPartners ;
/**
* @ var array Where restrictions for the query
*/
protected $_whereRestriction ;
/**
* @ var array Inner group conditions
*/
protected $_innerGroupConditions = array ();
/**
* @ var array Group conditions
*/
protected $_groupConditions ;
/**
* @ var array Result fields for the query
*/
protected $_resultFields = array ();
2021-06-21 12:43:19 +00:00
/**
*
* @ var array Column names of db table
*/
protected $_aTableColums = array ();
2016-10-06 15:57:01 +00:00
/**
* @ var string Encoding
*/
protected $_encoding ;
/**
* Stores all operators which are supported by GenericDB
* Unsupported operators are passed trough as - is .
* @ var array
*/
protected $_aOperators ;
/**
* Flag to select all fields in a query . Reduces the number of queries send
* to the database .
* @ var bool
*/
protected $_bAllMode = false ;
protected $_order ;
2021-01-26 18:41:21 +00:00
/**
2016-10-06 15:57:01 +00:00
* Constructor Function
*
* @ param string $sTable The table to use as information source
* @ param string $sPrimaryKey The primary key to use
* @ param int $iLifetime
*/
2021-01-26 18:41:21 +00:00
public function __construct ( $sTable , $sPrimaryKey , $iLifetime = 10 ) {
2016-10-06 15:57:01 +00:00
parent :: __construct ( $sTable , $sPrimaryKey , get_parent_class ( $this ), $iLifetime );
$this -> resetQuery ();
// Try to load driver
$this -> _initializeDriver ();
// Try to find out the current encoding
if ( isset ( $GLOBALS [ 'lang' ]) && isset ( $GLOBALS [ 'aLanguageEncodings' ])) {
$this -> setEncoding ( $GLOBALS [ 'aLanguageEncodings' ][ $GLOBALS [ 'lang' ]]);
}
$this -> _aOperators = array (
'=' , '!=' , '<>' , '<' , '>' , '<=' , '>=' , 'LIKE' , 'DIACRITICS'
);
}
/**
* Defines the reverse links for this table .
*
* Important : The class specified by $sForeignCollectionClass needs to be a
* collection class and has to exist .
* Define all links in the constructor of your object .
*
* @ param string $sForeignCollectionClass Specifies the foreign class to use
* @ return void
*/
2021-01-26 18:41:21 +00:00
protected function _setJoinPartner ( $sForeignCollectionClass ) {
2016-10-06 15:57:01 +00:00
if ( class_exists ( $sForeignCollectionClass )) {
// Add class
if ( ! in_array ( $sForeignCollectionClass , $this -> _JoinPartners )) {
$this -> _JoinPartners [] = strtolower ( $sForeignCollectionClass );
}
} else {
$sMsg = " Could not instanciate class [ $sForeignCollectionClass ] for use "
2021-01-26 18:41:21 +00:00
. " with _setJoinPartner in class " . get_class ( $this );
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
}
/**
* Method to set the accompanying item object .
*
* @ param string $sClassName Specifies the classname of item
* @ return void
*/
2021-01-26 18:41:21 +00:00
protected function _setItemClass ( $sClassName ) {
2016-10-06 15:57:01 +00:00
if ( class_exists ( $sClassName )) {
$this -> _itemClass = $sClassName ;
$this -> _itemClassInstance = new $sClassName ;
// Initialize driver in case the developer does a setItemClass-Call
// before calling the parent constructor
$this -> _initializeDriver ();
$this -> _driver -> setItemClassInstance ( $this -> _itemClassInstance );
} else {
$sMsg = " Could not instanciate class [ $sClassName ] for use with "
2021-01-26 18:41:21 +00:00
. " _setItemClass in class " . get_class ( $this );
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
}
/**
* Initializes the driver to use with GenericDB .
*
* @ param $bForceInit boolean If true , forces the driver to initialize , even if it already exists .
*/
2021-01-26 18:41:21 +00:00
protected function _initializeDriver ( $bForceInit = false ) {
2016-10-06 15:57:01 +00:00
if ( ! is_object ( $this -> _driver ) || $bForceInit == true ) {
$this -> _driver = new gdbMySQL ();
}
}
/**
* Sets the encoding .
* @ param string $sEncoding
*/
2021-01-26 18:41:21 +00:00
public function setEncoding ( $sEncoding ) {
2016-10-06 15:57:01 +00:00
$this -> _encoding = $sEncoding ;
$this -> _driver -> setEncoding ( $sEncoding );
}
/**
* Sets the query to use foreign tables in the resultset
* @ param string $sForeignClass The class of foreign table to use
*/
2021-01-26 18:41:21 +00:00
public function link ( $sForeignClass ) {
2016-10-06 15:57:01 +00:00
if ( class_exists ( $sForeignClass )) {
$this -> _links [ $sForeignClass ] = new $sForeignClass ;
} else {
$sMsg = " Could not find class [ $sForeignClass ] for use with link in class "
2021-01-26 18:41:21 +00:00
. get_class ( $this );
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
}
/**
* Sets the limit for results
* @ param int $iRowStart
* @ param int $iRowCount
*/
2021-01-26 18:41:21 +00:00
public function setLimit ( $iRowStart , $iRowCount ) {
2016-10-06 15:57:01 +00:00
$this -> _limitStart = $iRowStart ;
$this -> _limitCount = $iRowCount ;
}
/**
* Restricts a query with a where clause
* @ param string $sField
* @ param mixed $mRestriction
* @ param string $sOperator
*/
2021-01-26 18:41:21 +00:00
public function setWhere ( $sField , $mRestriction , $sOperator = '=' ) {
2016-10-06 15:57:01 +00:00
$sField = strtolower ( $sField );
2021-01-26 18:41:21 +00:00
$this -> _where [ 'global' ][ $sField ][ 'operator' ] = $sOperator ;
2016-10-06 15:57:01 +00:00
$this -> _where [ 'global' ][ $sField ][ 'restriction' ] = $mRestriction ;
}
/**
* Removes a previous set where clause ( @ see ItemCollection :: setWhere ) .
* @ param string $sField
* @ param mixed $mRestriction
* @ param string $sOperator
*/
2021-01-26 18:41:21 +00:00
public function deleteWhere ( $sField , $mRestriction , $sOperator = '=' ) {
2016-10-06 15:57:01 +00:00
$sField = strtolower ( $sField );
if ( isset ( $this -> _where [ 'global' ][ $sField ]) && is_array ( $this -> _where [ 'global' ][ $sField ])) {
2021-01-26 18:41:21 +00:00
if ( $this -> _where [ 'global' ][ $sField ][ 'operator' ] == $sOperator && $this -> _where [ 'global' ][ $sField ][ 'restriction' ] == $mRestriction ) {
2016-10-06 15:57:01 +00:00
unset ( $this -> _where [ 'global' ][ $sField ]);
}
}
}
/**
* Restricts a query with a where clause , groupable
* @ param string $sGroup
* @ param string $sField
* @ param mixed $mRestriction
* @ param string $sOperator
*/
2021-01-26 18:41:21 +00:00
public function setWhereGroup ( $sGroup , $sField , $mRestriction , $sOperator = '=' ) {
2016-10-06 15:57:01 +00:00
$sField = strtolower ( $sField );
$this -> _where [ 'groups' ][ $sGroup ][ $sField ][ 'operator' ] = $sOperator ;
$this -> _where [ 'groups' ][ $sGroup ][ $sField ][ 'restriction' ] = $mRestriction ;
}
/**
* Removes a previous set groupable where clause ( @ see ItemCollection :: setWhereGroup ) .
* @ param string $sGroup
* @ param string $sField
* @ param mixed $mRestriction
* @ param string $sOperator
*/
2021-01-26 18:41:21 +00:00
public function deleteWhereGroup ( $sGroup , $sField , $mRestriction , $sOperator = '=' ) {
2016-10-06 15:57:01 +00:00
$sField = strtolower ( $sField );
2021-01-26 18:41:21 +00:00
if ( is_array ( $this -> _where [ 'groups' ][ $sGroup ]) && isset ( $this -> _where [ 'groups' ][ $sGroup ][ $sField ]) && is_array ( $this -> _where [ 'groups' ][ $sGroup ][ $sField ])) {
if ( $this -> _where [ 'groups' ][ $sGroup ][ $sField ][ 'operator' ] == $sOperator && $this -> _where [ 'groups' ][ $sGroup ][ $sField ][ 'restriction' ] == $mRestriction ) {
2016-10-06 15:57:01 +00:00
unset ( $this -> _where [ 'groups' ][ $sGroup ][ $sField ]);
}
}
}
/**
* Defines how relations in one group are linked each together
* @ param string $sGroup
* @ param string $sCondition
*/
2021-01-26 18:41:21 +00:00
public function setInnerGroupCondition ( $sGroup , $sCondition = 'AND' ) {
2016-10-06 15:57:01 +00:00
$this -> _innerGroupConditions [ $sGroup ] = $sCondition ;
}
/**
* Defines how groups are linked to each other
* @ param string $sGroup1
* @ param string $sGroup2
* @ param string $sCondition
*/
2021-01-26 18:41:21 +00:00
public function setGroupCondition ( $sGroup1 , $sGroup2 , $sCondition = 'AND' ) {
2016-10-06 15:57:01 +00:00
$this -> _groupConditions [ $sGroup1 ][ $sGroup2 ] = $sCondition ;
}
/**
* Builds a where statement out of the setGroupWhere calls
*
* @ return array With all where statements
*/
2021-01-26 18:41:21 +00:00
protected function _buildGroupWhereStatements () {
2016-10-06 15:57:01 +00:00
$aWheres = array ();
$aGroupWhere = array ();
$mLastGroup = false ;
$sGroupWhereStatement = '' ;
// Find out if there are any defined groups
if ( count ( $this -> _where [ 'groups' ]) > 0 ) {
// Step trough all groups
foreach ( $this -> _where [ 'groups' ] as $groupname => $group ) {
$aWheres = array ();
// Fetch restriction, fields and operators and build single group
// where statements
foreach ( $group as $field => $item ) {
$aWheres [] = $this -> _driver -> buildOperator ( $field , $item [ 'operator' ], $item [ 'restriction' ]);
}
// Add completed substatements
$sOperator = 'AND' ;
if ( isset ( $this -> _innerGroupConditions [ $groupname ])) {
$sOperator = $this -> _innerGroupConditions [ $groupname ];
}
2021-01-26 18:41:21 +00:00
$aGroupWhere [ $groupname ] = implode ( ' ' . $sOperator . ' ' , $aWheres );
2016-10-06 15:57:01 +00:00
}
}
// Combine groups
foreach ( $aGroupWhere as $groupname => $group ) {
if ( $mLastGroup != false ) {
$sOperator = 'AND' ;
// Check if there's a group condition
if ( isset ( $this -> _groupConditions [ $groupname ])) {
if ( isset ( $this -> _groupConditions [ $groupname ][ $mLastGroup ])) {
$sOperator = $this -> _groupConditions [ $groupname ][ $mLastGroup ];
}
}
// Reverse check
if ( isset ( $this -> _groupConditions [ $mLastGroup ])) {
if ( isset ( $this -> _groupConditions [ $mLastGroup ][ $groupname ])) {
$sOperator = $this -> _groupConditions [ $mLastGroup ][ $groupname ];
}
}
2021-01-26 18:41:21 +00:00
$sGroupWhereStatement .= ' ' . $sOperator . ' (' . $group . ')' ;
2016-10-06 15:57:01 +00:00
} else {
2021-01-26 18:41:21 +00:00
$sGroupWhereStatement .= '(' . $group . ')' ;
2016-10-06 15:57:01 +00:00
}
$mLastGroup = $groupname ;
}
return $sGroupWhereStatement ;
}
/**
* Builds a where statement out of the setWhere calls
*
* @ return array With all where statements
*/
2021-01-26 18:41:21 +00:00
protected function _buildWhereStatements () {
2016-10-06 15:57:01 +00:00
$aWheres = array ();
// Build global where condition
foreach ( $this -> _where [ 'global' ] as $field => $item ) {
$aWheres [] = $this -> _driver -> buildOperator ( $field , $item [ 'operator' ], $item [ 'restriction' ]);
}
return ( implode ( ' AND ' , $aWheres ));
}
/**
* Fetches all tables which will be joined later on .
*
* The returned array has the following format :
* < pre >
* array (
* array ( fields ),
* array ( tables ),
* array ( joins ),
* array ( wheres )
* );
* </ pre >
*
* Notes :
* The table is the table name which needs to be added to the FROM clause
* The join statement which is inserted after the master table
* The where statement is combined with all other where statements
* The fields to select from
*
* @ todo Reduce complexity of this function , to much code ...
*
* @ param ? ? ? $ignoreRoot
* @ return array Array structure , see above
*/
2021-01-26 18:41:21 +00:00
protected function _fetchJoinTables ( $ignoreRoot ) {
2016-10-06 15:57:01 +00:00
$aParameters = array ();
$aFields = array ();
$aTables = array ();
$aJoins = array ();
$aWheres = array ();
// Fetch linked tables
foreach ( $this -> _links as $link => $object ) {
$matches = $this -> _findReverseJoinPartner ( strtolower ( get_class ( $this )), $link );
if ( $matches !== false ) {
if ( isset ( $matches [ 'desttable' ])) {
// Driver function: Build query parts
$aParameters [] = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$matches [ 'desttable' ],
strtolower ( $matches [ 'destclass' ]),
$matches [ 'key' ],
strtolower ( $matches [ 'sourceclass' ]),
$matches [ 'key' ]
2016-10-06 15:57:01 +00:00
);
} else {
foreach ( $matches as $match ) {
$aParameters [] = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$match [ 'desttable' ],
strtolower ( $match [ 'destclass' ]),
$match [ 'key' ],
strtolower ( $match [ 'sourceclass' ]),
$match [ 'key' ]
2016-10-06 15:57:01 +00:00
);
}
}
} else {
// Try forward search
$mobject = new $link ;
$matches = $mobject -> _findReverseJoinPartner ( $link , strtolower ( get_class ( $this )));
if ( $matches !== false ) {
if ( isset ( $matches [ 'desttable' ])) {
$i = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$mobject -> table ,
strtolower ( $link ),
$mobject -> primaryKey ,
strtolower ( $matches [ 'destclass' ]),
$matches [ 'key' ]
2016-10-06 15:57:01 +00:00
);
2021-01-26 18:41:21 +00:00
if ( $i [ 'field' ] == ( $link . '.' . $mobject -> primaryKey ) && $link == $ignoreRoot ) {
2016-10-06 15:57:01 +00:00
unset ( $i [ 'join' ]);
}
$aParameters [] = $i ;
} else {
foreach ( $matches as $match ) {
$xobject = new $match [ 'sourceclass' ];
$i = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$xobject -> table ,
strtolower ( $match [ 'sourceclass' ]),
$xobject -> primaryKey ,
strtolower ( $match [ 'destclass' ]),
$match [ 'key' ]
2016-10-06 15:57:01 +00:00
);
2021-01-26 18:41:21 +00:00
if ( $i [ 'field' ] == ( $match [ 'sourceclass' ] . '.' . $xobject -> primaryKey ) && $match [ 'sourceclass' ] == $ignoreRoot ) {
2016-10-06 15:57:01 +00:00
unset ( $i [ 'join' ]);
}
array_unshift ( $aParameters , $i );
}
}
} else {
$bDualSearch = true ;
// Check first if we are a instance of another class
foreach ( $mobject -> _JoinPartners as $sJoinPartner ) {
if ( class_exists ( $sJoinPartner )) {
if ( is_subclass_of ( $this , $sJoinPartner )) {
$matches = $mobject -> _findReverseJoinPartner ( $link , strtolower ( $sJoinPartner ));
if ( $matches !== false ) {
if ( $matches [ 'destclass' ] == strtolower ( $sJoinPartner )) {
$matches [ 'destclass' ] = get_class ( $this );
if ( isset ( $matches [ 'desttable' ])) {
$i = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$mobject -> table ,
strtolower ( $link ),
$mobject -> primaryKey ,
strtolower ( $matches [ 'destclass' ]),
$matches [ 'key' ]
2016-10-06 15:57:01 +00:00
);
2021-01-26 18:41:21 +00:00
if ( $i [ 'field' ] == ( $link . '.' . $mobject -> primaryKey ) && $link == $ignoreRoot ) {
2016-10-06 15:57:01 +00:00
unset ( $i [ 'join' ]);
}
$aParameters [] = $i ;
} else {
foreach ( $matches as $match ) {
$xobject = new $match [ 'sourceclass' ];
$i = $this -> _driver -> buildJoinQuery (
2021-01-26 18:41:21 +00:00
$xobject -> table ,
strtolower ( $match [ 'sourceclass' ]),
$xobject -> primaryKey ,
strtolower ( $match [ 'destclass' ]),
$match [ 'key' ]
2016-10-06 15:57:01 +00:00
);
2021-01-26 18:41:21 +00:00
if ( $i [ 'field' ] == ( $match [ 'sourceclass' ] . '.' . $xobject -> primaryKey ) && $match [ 'sourceclass' ] == $ignoreRoot ) {
2016-10-06 15:57:01 +00:00
unset ( $i [ 'join' ]);
}
array_unshift ( $aParameters , $i );
}
}
$bDualSearch = false ;
}
}
}
}
}
if ( $bDualSearch ) {
// Try dual-side search
$forward = $this -> _resolveLinks ();
$reverse = $mobject -> _resolveLinks ();
$result = array_intersect ( $forward , $reverse );
if ( count ( $result ) > 0 ) {
// Found an intersection, build references to it
foreach ( $result as $value ) {
$oIntersect = new $value ;
$oIntersect -> link ( strtolower ( get_class ( $this )));
$oIntersect -> link ( strtolower ( get_class ( $mobject )));
$aIntersectParameters = $oIntersect -> _fetchJoinTables ( $ignoreRoot );
$aFields = array_merge ( $aIntersectParameters [ 'fields' ], $aFields );
$aTables = array_merge ( $aIntersectParameters [ 'tables' ], $aTables );
$aJoins = array_merge ( $aIntersectParameters [ 'joins' ], $aJoins );
$aWheres = array_merge ( $aIntersectParameters [ 'wheres' ], $aWheres );
}
} else {
$sMsg = " Could not find join partner for class [ $link ] in class "
2021-01-26 18:41:21 +00:00
. get_class ( $this ) . " in neither forward nor reverse direction. " ;
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
}
}
}
}
// Add this class
2021-01-26 18:41:21 +00:00
$aFields [] = strtolower ( strtolower ( get_class ( $this ))) . '.' . $this -> primaryKey ;
2016-10-06 15:57:01 +00:00
// Make the parameters unique
foreach ( $aParameters as $parameter ) {
array_unshift ( $aFields , $parameter [ 'field' ]);
array_unshift ( $aTables , $parameter [ 'table' ]);
array_unshift ( $aJoins , $parameter [ 'join' ]);
array_unshift ( $aWheres , $parameter [ 'where' ]);
}
$aFields = array_filter ( array_unique ( $aFields ));
$aTables = array_filter ( array_unique ( $aTables ));
$aJoins = array_filter ( array_unique ( $aJoins ));
$aWheres = array_filter ( array_unique ( $aWheres ));
return array (
'fields' => $aFields , 'tables' => $aTables , 'joins' => $aJoins , 'wheres' => $aWheres
);
}
/**
* Resolves links ( class names of joined partners )
*
* @ return array
*/
2021-01-26 18:41:21 +00:00
protected function _resolveLinks () {
2016-10-06 15:57:01 +00:00
$aResolvedLinks = array ();
$aResolvedLinks [] = strtolower ( get_class ( $this ));
foreach ( $this -> _JoinPartners as $link ) {
$class = new $link ;
$aResolvedLinks = array_merge ( $class -> _resolveLinks (), $aResolvedLinks );
}
return $aResolvedLinks ;
}
/**
* Resets the properties
*/
2021-01-26 18:41:21 +00:00
public function resetQuery () {
2016-10-06 15:57:01 +00:00
$this -> setLimit ( 0 , 0 );
$this -> _JoinPartners = array ();
$this -> _forwardJoinPartners = array ();
$this -> _links = array ();
$this -> _where [ 'global' ] = array ();
$this -> _where [ 'groups' ] = array ();
$this -> _groupConditions = array ();
$this -> _resultFields = array ();
2021-06-21 12:43:19 +00:00
$this -> _aTableColums = array ();
2016-10-06 15:57:01 +00:00
}
/**
* Builds and runs the query
*
* @ return bool
*/
2021-01-26 18:41:21 +00:00
public function query () {
2016-10-06 15:57:01 +00:00
if ( ! isset ( $this -> _itemClassInstance )) {
$sMsg = " GenericDB can't use query() if no item class is set via setItemClass " ;
cWarning ( __FILE__ , __LINE__ , $sMsg );
return false ;
}
$aGroupWhereStatements = $this -> _buildGroupWhereStatements ();
$sWhereStatements = $this -> _buildWhereStatements ();
$aParameters = $this -> _fetchJoinTables ( strtolower ( get_class ( $this )));
$aStatement = array (
'SELECT' ,
implode ( ', ' , ( array_merge ( $aParameters [ 'fields' ], $this -> _resultFields ))),
'FROM' ,
'`' . $this -> table . '` AS ' . strtolower ( get_class ( $this ))
);
if ( count ( $aParameters [ 'tables' ]) > 0 ) {
$aStatement [] = implode ( ', ' , $aParameters [ 'tables' ]);
}
if ( count ( $aParameters [ 'joins' ]) > 0 ) {
$aStatement [] = implode ( ' ' , $aParameters [ 'joins' ]);
}
$aWheres = array ();
if ( count ( $aParameters [ 'wheres' ]) > 0 ) {
$aWheres [] = implode ( ', ' , $aParameters [ 'wheres' ]);
}
if ( $aGroupWhereStatements != '' ) {
$aWheres [] = $aGroupWhereStatements ;
}
if ( $sWhereStatements != '' ) {
$aWheres [] = $sWhereStatements ;
}
if ( count ( $aWheres ) > 0 ) {
2021-01-26 18:41:21 +00:00
$aStatement [] = 'WHERE ' . implode ( ' AND ' , $aWheres );
2016-10-06 15:57:01 +00:00
}
if ( $this -> _order != '' ) {
2021-01-26 18:41:21 +00:00
$aStatement [] = 'ORDER BY ' . $this -> _order ;
2016-10-06 15:57:01 +00:00
}
if ( $this -> _limitStart > 0 || $this -> _limitCount > 0 ) {
$iRowStart = intval ( $this -> _limitStart );
$iRowCount = intval ( $this -> _limitCount );
$aStatement [] = " LIMIT $iRowStart , $iRowCount " ;
}
$sql = implode ( ' ' , $aStatement );
$result = $this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
// @todo disable all mode in this method for the moment. It has to be verified,
// if enabling will result in negative side effects.
$this -> _bAllMode = false ;
return ( $result ) ? true : false ;
}
/**
* Sets the result order part of the query
* ( e . g . " fieldname " , " fieldname DESC " , " fieldname DESC, field2name ASC " )
* @ param string $order
*/
2021-01-26 18:41:21 +00:00
public function setOrder ( $order ) {
2016-10-06 15:57:01 +00:00
$this -> _order = strtolower ( $order );
}
/**
* Adds a result field
2021-06-11 06:34:24 +00:00
* @ param string | array $mField
2016-10-06 15:57:01 +00:00
*/
2021-06-21 12:43:19 +00:00
public function addResultField ( $mField , $bAll = false ) {
if ( ! empty ( $mField ) && ! is_array ( $mField )) {
2021-06-11 06:34:24 +00:00
$mField = array ( $mField );
2021-06-21 12:43:19 +00:00
} else if ( $bAll && empty ( $this -> _aTableColums )) {
$aTemp = $this -> db -> metadata ( $this -> table );
foreach ( $aTemp as $aMeta ) {
$this -> _aTableColums [] = $aMeta [ 'name' ];
}
$mField = $this -> _aTableColums ;
2021-06-11 06:34:24 +00:00
}
foreach ( $mField as $sField ) {
$sField = strtolower ( $sField );
if ( ! in_array ( $sField , $this -> _resultFields )) {
$this -> _resultFields [] = $sField ;
}
2016-10-06 15:57:01 +00:00
}
}
/**
* Removes existing result field
2021-06-11 06:34:24 +00:00
* @ param string | array $mField
2016-10-06 15:57:01 +00:00
*/
2021-06-11 06:34:24 +00:00
public function removeResultField ( $mField ) {
if ( ! is_array ( $mField )) {
$mField = array ( $mField );
}
foreach ( $mField as $sField ) {
$sField = strtolower ( $sField );
$key = array_search ( $sField , $this -> _resultFields );
if ( $key !== false ) {
unset ( $this -> _resultFields [ $key ]);
}
2016-10-06 15:57:01 +00:00
}
}
/**
* Returns reverse join partner .
*
* @ param string $sParentClass
* @ param string $sClassName
* @ param array | bool
*/
2021-01-26 18:41:21 +00:00
protected function _findReverseJoinPartner ( $sParentClass , $sClassName ) {
2016-10-06 15:57:01 +00:00
// Make the parameters lowercase, as get_class is buggy
2021-01-26 18:41:21 +00:00
$sClassName = strtolower ( $sClassName );
2016-10-06 15:57:01 +00:00
$sParentClass = strtolower ( $sParentClass );
// Check if we found a direct link
if ( in_array ( $sClassName , $this -> _JoinPartners )) {
$obj = new $sClassName ;
return array (
'desttable' => $obj -> table , 'destclass' => $sClassName ,
'sourceclass' => $sParentClass , 'key' => $obj -> primaryKey
);
} else {
// Recurse all items
foreach ( $this -> _JoinPartners as $join => $tmpClassname ) {
$obj = new $tmpClassname ;
$status = $obj -> _findReverseJoinPartner ( $tmpClassname , $sClassName );
if ( is_array ( $status )) {
$returns = array ();
if ( ! isset ( $status [ 'desttable' ])) {
foreach ( $status as $subitem ) {
$returns [] = $subitem ;
}
} else {
$returns [] = $status ;
}
$obj = new $tmpClassname ;
$returns [] = array (
'desttable' => $obj -> table , 'destclass' => $tmpClassname ,
'sourceclass' => $sParentClass , 'key' => $obj -> primaryKey
);
return ( $returns );
}
}
}
return false ;
}
/**
* Selects all entries from the database . Objects are loaded using their primary key .
*
* @ param string $sWhere Specifies the where clause .
* @ param string $sGroupBy Specifies the group by clause .
* @ param string $sOrderBy Specifies the order by clause .
* @ param string $sLimit Specifies the limit by clause .
* @ return bool True on success , otherwhise false
*/
2021-01-26 18:41:21 +00:00
public function select ( $sWhere = '' , $sGroupBy = '' , $sOrderBy = '' , $sLimit = '' ) {
2016-10-06 15:57:01 +00:00
unset ( $this -> objects );
if ( $sWhere == '' ) {
$sWhere = '' ;
} else {
2021-01-26 18:41:21 +00:00
$sWhere = ' WHERE ' . $sWhere ;
2016-10-06 15:57:01 +00:00
}
if ( $sGroupBy != '' ) {
2021-01-26 18:41:21 +00:00
$sGroupBy = ' GROUP BY ' . $sGroupBy ;
2016-10-06 15:57:01 +00:00
}
if ( $sOrderBy != '' ) {
2021-01-26 18:41:21 +00:00
$sOrderBy = ' ORDER BY ' . $sOrderBy ;
2016-10-06 15:57:01 +00:00
}
if ( $sLimit != '' ) {
2021-01-26 18:41:21 +00:00
$sLimit = ' LIMIT ' . $sLimit ;
2016-10-06 15:57:01 +00:00
}
$sFields = ( $this -> _settings [ 'select_all_mode' ]) ? '*' : $this -> primaryKey ;
$sql = 'SELECT ' . $sFields . ' FROM `' . $this -> table . '`' . $sWhere
2021-01-26 18:41:21 +00:00
. $sGroupBy . $sOrderBy . $sLimit ;
2016-10-06 15:57:01 +00:00
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
$this -> _bAllMode = $this -> _settings [ 'select_all_mode' ];
if ( $this -> db -> num_rows () == 0 ) {
return false ;
} else {
return true ;
}
}
/**
* Selects all entries from the database . Objects are loaded using their primary key .
*
* @ param string $sDistinct Specifies if distinct will be added to the SQL
* statement ( $sDistinct !== '' -> DISTINCT )
* @ param string $sFrom Specifies the additional from clause ( e . g .
* 'con_news_groups AS groups, con_news_groupmembers AS groupmembers' ) .
* @ param string $sWhere Specifies the where clause .
* @ param string $sGroupBy Specifies the group by clause .
* @ param string $sOrderBy Specifies the order by clause .
* @ param string $sLimit Specifies the limit by clause .
* @ return bool True on success , otherwhise false
* @ author HerrB
*/
2021-01-26 18:41:21 +00:00
public function flexSelect ( $sDistinct = '' , $sFrom = '' , $sWhere = '' , $sGroupBy = '' , $sOrderBy = '' , $sLimit = '' ) {
2016-10-06 15:57:01 +00:00
unset ( $this -> objects );
if ( $sDistinct != '' ) {
$sDistinct = 'DISTINCT ' ;
}
if ( $sFrom != '' ) {
2021-01-26 18:41:21 +00:00
$sFrom = ', ' . $sFrom ;
2016-10-06 15:57:01 +00:00
}
if ( $sWhere != '' ) {
2021-01-26 18:41:21 +00:00
$sWhere = ' WHERE ' . $sWhere ;
2016-10-06 15:57:01 +00:00
}
if ( $sGroupBy != '' ) {
2021-01-26 18:41:21 +00:00
$sGroupBy = ' GROUP BY ' . $sGroupBy ;
2016-10-06 15:57:01 +00:00
}
if ( $sOrderBy != '' ) {
2021-01-26 18:41:21 +00:00
$sOrderBy = ' ORDER BY ' . $sOrderBy ;
2016-10-06 15:57:01 +00:00
}
if ( $sLimit != '' ) {
2021-01-26 18:41:21 +00:00
$sLimit = ' LIMIT ' . $sLimit ;
2016-10-06 15:57:01 +00:00
}
$sql = 'SELECT ' . $sDistinct . strtolower ( get_class ( $this )) . '.' . $this -> primaryKey
2021-01-26 18:41:21 +00:00
. ' AS ' . $this -> primaryKey . ' FROM `' . $this -> table . '` AS ' . strtolower ( get_class ( $this ))
. $sFrom . $sWhere . $sGroupBy . $sOrderBy . $sLimit ;
2016-10-06 15:57:01 +00:00
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
// @todo disable all mode in this method
$this -> _bAllMode = false ;
if ( $this -> db -> num_rows () == 0 ) {
return false ;
} else {
return true ;
}
}
/**
* Checks if a specific entry exists .
*
* @ param mixed $mId The id to check for ( could be numeric or string )
* @ return bool True if object exists , false if not
*/
2021-01-26 18:41:21 +00:00
public function exists ( $mId ) {
2016-10-06 15:57:01 +00:00
$oDb = $this -> _getSecondDBInstance ();
$sql = " SELECT `%s` FROM %s WHERE %s='%s' " ;
$oDb -> query ( $sql , $this -> primaryKey , $this -> table , $this -> primaryKey , $mId );
return ( $oDb -> next_record ()) ? true : false ;
}
/**
* Advances to the next item in the database .
*
* @ return Item | bool The next object , or false if no more objects
*/
2021-01-26 18:41:21 +00:00
public function next () {
2016-10-06 15:57:01 +00:00
if ( $this -> db -> next_record ()) {
2021-01-26 18:41:21 +00:00
if ( $this -> _bAllMode ) {
2016-10-06 15:57:01 +00:00
$aRs = $this -> db -> toArray ( DB_ConLite :: FETCH_BOTH );
return $this -> loadItem ( $aRs );
} else {
return $this -> loadItem ( $this -> db -> f ( $this -> primaryKey ));
}
} else {
return false ;
}
}
/**
* Fetches the resultset related to current loaded primary key as a object
*
* @ param Item
*/
2021-01-26 18:41:21 +00:00
public function fetchObject ( $sClassName ) {
2016-10-06 15:57:01 +00:00
$sKey = strtolower ( $sClassName );
if ( ! is_object ( $this -> _collectionCache [ $sKey ])) {
$this -> _collectionCache [ $sKey ] = new $sClassName ;
}
$obj = $this -> _collectionCache [ $sKey ];
return $obj -> loadItem ( $this -> db -> f ( $obj -> primaryKey ));
}
/**
* Both arrays are optional . If both empty you will get an result using field stored in primaryKey
*
* $aFields = array with the fields to fetch . Notes :
* If the array contains keys , the key will be used as alias for the field . Example :
* array ( 'id' => 'idcat' ) will put 'idcat' into field 'id'
*
* $aObjects = array with the objects to fetch . Notes :
* If the array contains keys , the key will be used as alias for the object . If you specify
* more than one object with the same key , the array will be multi - dimensional .
*
* @ param array $aFields
* @ param array $aObjects
* @ return array
*/
public function fetchTable ( array $aFields = array (), array $aObjects = array ()) {
$row = 1 ;
$aTable = array ();
2021-06-21 12:43:19 +00:00
if ( ! empty ( $this -> _aTableColums )) {
$aFields = $this -> _aTableColums ;
}
2021-01-26 18:41:21 +00:00
if ( empty ( $aFields ) && empty ( $aObjects )) {
2016-10-06 15:57:01 +00:00
$aFields = array ( $this -> primaryKey );
}
$this -> db -> seek ( 0 );
while ( $this -> db -> next_record ()) {
foreach ( $aFields as $alias => $field ) {
//if ($alias != '') {
if ( is_string ( $alias )) {
$aTable [ $row ][ $alias ] = $this -> db -> f ( $field );
} else {
$aTable [ $row ][ $field ] = $this -> db -> f ( $field );
}
}
// Fetch objects
2021-01-26 18:41:21 +00:00
if ( ! empty ( $aObjects )) {
2016-10-06 15:57:01 +00:00
foreach ( $aObjects as $alias => $object ) {
if ( $alias != '' ) {
if ( isset ( $aTable [ $row ][ $alias ])) {
// Is set, check for array. If no array, create one
if ( is_array ( $aTable [ $row ][ $alias ])) {
$aTable [ $row ][ $alias ][] = $this -> fetchObject ( $object );
} else {
// $tmpObj = $aTable[$row][$alias];
$aTable [ $row ][ $alias ] = array ();
$aTable [ $row ][ $alias ][] = $this -> fetchObject ( $object );
}
} else {
$aTable [ $row ][ $alias ] = $this -> fetchObject ( $object );
}
} else {
$aTable [ $row ][ $object ] = $this -> fetchObject ( $object );
}
}
}
2021-01-26 18:41:21 +00:00
$row ++ ;
2016-10-06 15:57:01 +00:00
}
$this -> db -> seek ( 0 );
return $aTable ;
}
/**
* Returns an array of arrays
* @ param array $aObjects With the correct order of the objects
* @ return array Result
*/
2021-01-26 18:41:21 +00:00
public function queryAndFetchStructured ( array $aObjects ) {
2016-10-06 15:57:01 +00:00
$aOrder = array ();
$aFetchObjects = array ();
$aResult = array ();
foreach ( $aObjects as $object ) {
$x = new $object ;
$object = strtolower ( $object );
2021-01-26 18:41:21 +00:00
$aOrder [] = $object . '.' . $x -> primaryKey . ' ASC' ;
2016-10-06 15:57:01 +00:00
$aFetchObjects [] = $x ;
}
$this -> setOrder ( implode ( ', ' , $aOrder ));
$this -> query ();
$this -> db -> seek ( 0 );
while ( $this -> db -> next_record ()) {
$aResult = $this -> _recursiveStructuredFetch ( $aFetchObjects , $aResult );
}
return $aResult ;
}
2021-01-26 18:41:21 +00:00
protected function _recursiveStructuredFetch ( array $aObjects , array $aResult ) {
2016-10-06 15:57:01 +00:00
$i = array_shift ( $aObjects );
$value = $this -> db -> f ( $i -> primaryKey );
if ( ! is_null ( $value )) {
$aResult [ $value ][ 'class' ] = strtolower ( get_class ( $i ));
$aResult [ $value ][ 'object' ] = $i -> loadItem ( $value );
if ( count ( $aObjects ) > 0 ) {
$aResult [ $value ][ 'items' ] = $this -> _recursiveStructuredFetch ( $aObjects , $aResult [ $value ][ 'items' ]);
}
}
return $aResult ;
}
/**
* Returns the amount of returned items
* @ return int Number of rows
*/
2021-01-26 18:41:21 +00:00
public function count () {
2016-10-06 15:57:01 +00:00
return ( $this -> db -> num_rows ());
}
/**
* Loads a single entry by it ' s id .
*
* @ param string | int $id The primary key of the item to load .
* @ return Item The loaded item
*/
2021-01-26 18:41:21 +00:00
public function fetchById ( $id ) {
2016-10-06 15:57:01 +00:00
if ( is_numeric ( $id )) {
$id = ( int ) $id ;
} elseif ( is_string ( $id )) {
$id = $this -> escape ( $id );
}
return $this -> loadItem ( $id );
}
/**
* Loads a single object from the database .
*
* @ param mixed $mItem The primary key of the item to load or a recordset
* with itemdata ( array ) to inject to the item object .
* @ return Item The newly created object
* @ throws Contenido_ItemException If item class is not set
*/
2021-01-26 18:41:21 +00:00
public function loadItem ( $mItem ) {
2016-10-06 15:57:01 +00:00
if ( empty ( $this -> _itemClass )) {
$sMsg = " ItemClass has to be set in the constructor of class "
2021-01-26 18:41:21 +00:00
. get_class ( $this ) . " ) " ;
2016-10-06 15:57:01 +00:00
throw new Contenido_ItemException ( $sMsg );
}
if ( ! is_object ( $this -> _iteratorItem )) {
$this -> _iteratorItem = new $this -> _itemClass ();
}
if ( is_array ( $mItem )) {
$this -> _iteratorItem -> loadByRecordSet ( $mItem );
} else {
$this -> _iteratorItem -> loadByPrimaryKey ( $mItem );
}
return $this -> _iteratorItem ;
}
/**
* Creates a new item in the table and loads it afterwards .
*
* @ param string $primaryKeyValue Optional parameter for direct input of primary key value
* @ return Item The newly created object
*/
2021-08-23 13:38:26 +00:00
public function createNewItem ( $aData = NULL ) {
/* @var $oDb DB_ConLite */
2021-01-26 18:41:21 +00:00
$oDb = $this -> _getSecondDBInstance ();
if ( is_null ( $aData ) || empty ( $aData )) {
2017-08-09 20:03:52 +00:00
$iNextId = $oDb -> nextid ( $this -> table );
2021-01-26 18:41:21 +00:00
} else if ( is_array ( $aData ) && key_exists ( $this -> primaryKey , $aData )) {
2017-08-09 20:03:52 +00:00
$iNextId = ( int ) $aData [ $this -> primaryKey ];
} else {
$iNextId = ( int ) $aData ;
2021-01-26 18:41:21 +00:00
}
$sql = 'INSERT INTO `%s` (%s) VALUES (%d)' ;
2016-10-06 15:57:01 +00:00
$oDb -> query ( $sql , $this -> table , $this -> primaryKey , $iNextId );
return $this -> loadItem ( $iNextId );
}
/**
* Deletes an item in the table .
* Deletes also cached e entry and any existing properties .
*
* @ param mixed $mId Id of entry to delete
* @ return bool
*/
2021-01-26 18:41:21 +00:00
public function delete ( $mId ) {
2016-10-06 15:57:01 +00:00
$result = $this -> _delete ( $mId );
return $result ;
}
/**
* Deletes all found items in the table matching the rules in the passed where clause .
* Deletes also cached e entries and any existing properties .
*
* @ param string $sWhere The where clause of the SQL statement
* @ return int Number of deleted entries
*/
2021-01-26 18:41:21 +00:00
public function deleteByWhereClause ( $sWhere ) {
2016-10-06 15:57:01 +00:00
$oDb = $this -> _getSecondDBInstance ();
$aIds = array ();
$numDeleted = 0 ;
// get all ids
$sql = 'SELECT ' . $this -> primaryKey . ' AS pk FROM `' . $this -> table . '` WHERE ' . $sWhere ;
$oDb -> query ( $sql );
while ( $oDb -> next_record ()) {
$aIds [] = $oDb -> f ( 'pk' );
}
// delete entries by their ids
foreach ( $aIds as $id ) {
if ( $this -> _delete ( $id )) {
$numDeleted ++ ;
}
}
return $numDeleted ;
}
/**
* Deletes all found items in the table matching the passed field and it ' s value .
* Deletes also cached e entries and any existing properties .
*
* @ param string $sField The field name
* @ param mixed $mValue The value of the field
* @ return int Number of deleted entries
*/
2021-01-26 18:41:21 +00:00
public function deleteBy ( $sField , $mValue ) {
2016-10-06 15:57:01 +00:00
$oDb = $this -> _getSecondDBInstance ();
$aIds = array ();
$numDeleted = 0 ;
// get all ids
if ( is_string ( $mValue )) {
$sql = " SELECT %s AS pk FROM `%s` WHERE `%s` = '%s' " ;
} else {
$sql = " SELECT %s AS pk FROM `%s` WHERE `%s` = %d " ;
}
$oDb -> query ( $sql , $this -> primaryKey , $this -> table , $sField , $mValue );
while ( $oDb -> next_record ()) {
$aIds [] = $oDb -> f ( 'pk' );
}
// delete entries by their ids
foreach ( $aIds as $id ) {
if ( $this -> _delete ( $id )) {
$numDeleted ++ ;
}
}
return $numDeleted ;
}
/**
* Deletes an item in the table , deletes also existing cache entries and
* properties of the item .
*
* @ param mixed $mId Id of entry to delete
* @ return bool
*/
protected function _delete ( $mId ) {
2021-01-26 18:41:21 +00:00
2016-10-06 15:57:01 +00:00
// delete cache entry
self :: $_oCache -> removeItem ( $mId );
// delete the property values
$oProperties = $this -> _getPropertiesCollectionInstance ();
$oProperties -> deleteProperties ( $this -> primaryKey , $mId );
2021-01-26 18:41:21 +00:00
2016-10-06 15:57:01 +00:00
$oDb = $this -> _getSecondDBInstance ();
// delete db entry
$sql = " DELETE FROM `%s` WHERE %s = '%s' " ;
$oDb -> query ( $sql , $this -> table , $this -> primaryKey , $mId );
2021-01-26 18:41:21 +00:00
return (( $oDb -> affected_rows () > 0 ) ? true : false );
2016-10-06 15:57:01 +00:00
}
/**
* Fetches an array of fields from the database .
*
* Example :
* $i = $object -> fetchArray ( 'idartlang' , array ( 'idlang' , 'name' ));
*
* could result in :
* $i [ 5 ] = array ( 'idlang' => 5 , 'name' => 'My Article' );
*
* Important : If you don ' t pass an array for fields , the function
* doesn ' t create an array .
* @ param string $sKey Name of the field to use for the key
* @ param mixed $mFields String or array
* @ return array Resulting array
*/
2021-01-26 18:41:21 +00:00
public function fetchArray ( $sKey , $mFields ) {
2016-10-06 15:57:01 +00:00
$aResult = array ();
while ( $item = $this -> next ()) {
if ( is_array ( $mFields )) {
foreach ( $mFields as $value ) {
$aResult [ $item -> get ( $sKey )][ $value ] = $item -> get ( $value );
}
} else {
$aResult [ $item -> get ( $sKey )] = $item -> get ( $mFields );
}
}
return $aResult ;
}
}
/**
* Class Item
* Abstract class for database based items .
*
* @ author Timo A . Hummel < Timo . Hummel @ 4 fb . de >
* @ author Murat Purc < murat @ purc . de >
* @ version 0.3
* @ copyright four for business 2003
*/
2021-01-26 18:41:21 +00:00
abstract class Item extends cItemBaseAbstract {
2016-10-06 15:57:01 +00:00
/**
* Storage of the source table to use for the user informations
* @ var array
*/
public $values ;
/**
* Storage of the fields which were modified , where the keys are the
* fieldnames and the values just simple booleans .
* @ var array
*/
protected $modifiedValues ;
/**
* Stores the old primary key , just in case somebody wants to change it
* @ var string
*/
protected $oldPrimaryKey ;
/**
* List of funcion names of the filters used when data is stored to the db .
* @ var array
*/
protected $_arrInFilters = array ( 'urlencode' , 'clHtmlSpecialChars' , 'addslashes' );
/**
* List of funcion names of the filtersused when data is retrieved from the db
* @ var array
*/
protected $_arrOutFilters = array ( 'stripslashes' , 'htmldecode' , 'urldecode' );
/**
* Class name of meta object
* @ var string
*/
protected $_metaObject ;
2021-08-23 13:38:26 +00:00
/**
* Last executed SQL statement
*
* @ var string
*/
protected $_lastSQL ;
2016-10-06 15:57:01 +00:00
/**
* Constructor function
*
* @ param string $sTable The table to use as information source
* @ param string $sPrimaryKey The primary key to use
* @ param int $iLifetime
*/
2021-01-26 18:41:21 +00:00
public function __construct ( $sTable = '' , $sPrimaryKey = '' , $iLifetime = 10 ) {
2016-10-06 15:57:01 +00:00
parent :: __construct ( $sTable , $sPrimaryKey , get_parent_class ( $this ), $iLifetime );
}
2021-01-26 18:41:21 +00:00
function __destruct () {
2016-10-06 15:57:01 +00:00
//print_r(self::$_oCache);
}
/**
* Loads an item by colum / field from the database .
*
* @ param string $sField Specifies the field
* @ param mixed $mValue Specifies the value
* @ param bool $bSafe Use inFilter or not
* @ return bool True if the load was successful
*/
2021-01-26 18:41:21 +00:00
public function loadBy ( $sField , $mValue , $bSafe = true ) {
2016-10-06 15:57:01 +00:00
if ( $bSafe ) {
$mValue = $this -> _inFilter ( $mValue );
}
// check, if cache contains a matching entry
$aRecordSet = null ;
if ( $sField === $this -> primaryKey ) {
2021-01-26 18:41:21 +00:00
$aRecordSet = self :: $_oCache -> getItem ( $this -> table . " _ " . $mValue );
2016-10-06 15:57:01 +00:00
} else {
2021-01-26 18:41:21 +00:00
$aRecordSet = self :: $_oCache -> getItemByProperty ( $this -> table . " _ " . $sField , $mValue );
2016-10-06 15:57:01 +00:00
}
if ( $aRecordSet ) {
// entry in cache found, load entry from cache
$this -> loadByRecordSet ( $aRecordSet );
return true ;
}
// SQL-Statement to select by field
2021-01-26 18:41:21 +00:00
$sql = sprintf ( " SELECT * FROM `%s` WHERE %s = '%s' " , $this -> table , $sField , $mValue );
2016-10-06 15:57:01 +00:00
//$sql = $this->db->prepare($sql, $this->table, $sField, $mValue);
// Query the database
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
if ( $this -> db -> num_rows () > 1 ) {
$sMsg = " Tried to load a single line with field $sField and value $mValue from "
2021-01-26 18:41:21 +00:00
. $this -> table . " but found more than one row " ;
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
// Advance to the next record, return false if nothing found
if ( ! $this -> db -> next_record ()) {
return false ;
}
$this -> loadByRecordSet ( $this -> db -> toArray ());
return true ;
}
2021-08-23 13:38:26 +00:00
public function loadByMany ( array $aAttributes , $bSafe = true ) {
$this -> _resetItem ();
if ( $bSafe ) {
$aAttributes = $this -> _inFilter ( $aAttributes );
}
// @todo add cache here
// SQL-Statement to select by fields
$sql = 'SELECT * FROM `:mytab` WHERE' ;
foreach ( array_keys ( $aAttributes ) as $sKey ) {
// add quotes if key is a string
if ( is_string ( $sKey )) {
$sql .= " $sKey = ': $sKey ' AND " ;
} else {
$sql .= " $sKey = : $sKey AND " ;
}
}
// strip the last " AND" token
$sql = cString :: getPartOfString ( $sql , 0 , cString :: getStringLength ( $sql ) - 4 );
$sql = $this -> db -> _prepareQueryf ( $sql , array_merge ( array (
'mytab' => $this -> table
), $aAttributes ));
// Query the database
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
if ( $this -> db -> num_rows () > 1 ) {
$msg = 'Tried to load a single line with fields ' . print_r ( array_keys ( $aAttributes ), true ) . ' and values ' . print_r ( array_values ( $aAttributes ), true ) . ' from ' . $this -> table . ' but found more than one row' ;
throw new Contenido_ItemException ( $msg );
}
// Advance to the next record, return false if nothing found
if ( ! $this -> db -> next_record ()) {
return false ;
}
$this -> loadByRecordSet ( $this -> db -> toArray ());
$this -> _setLoaded ( true );
return true ;
}
2016-10-06 15:57:01 +00:00
/**
* Loads an item by passed where clause from the database .
* This function is expensive , since it executes allways a query to the database
* to retrieve the primary key , even if the record set is aleady cached .
* NOTE : Passed value has to be escaped before . This will not be done by this function .
*
* @ param string $sWhere The where clause like 'idart = 123 AND idlang = 1'
* @ return bool True if the load was successful
*/
2021-01-26 18:41:21 +00:00
protected function _loadByWhereClause ( $sWhere ) {
2016-10-06 15:57:01 +00:00
// SQL-Statement to select by whee clause
2021-01-26 18:41:21 +00:00
$sql = sprintf ( " SELECT %s AS pk FROM `%s` WHERE " , $this -> primaryKey , $this -> table ) . ( string ) $sWhere ;
2016-10-06 15:57:01 +00:00
//$sql = $this->db->prepare($sql, $this->primaryKey, $this->table);
// Query the database
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
if ( $this -> db -> num_rows () > 1 ) {
$sMsg = " Tried to load a single line with where clause ' " . $sWhere . " ' from "
2021-01-26 18:41:21 +00:00
. $this -> table . " but found more than one row " ;
2016-10-06 15:57:01 +00:00
cWarning ( __FILE__ , __LINE__ , $sMsg );
}
// Advance to the next record, return false if nothing found
if ( ! $this -> db -> next_record ()) {
return false ;
}
$id = $this -> db -> f ( 'pk' );
return $this -> loadByPrimaryKey ( $id );
}
/**
* Loads an item by ID from the database .
*
* @ param string $mValue Specifies the primary key value
* @ return bool True if the load was successful
*/
2021-01-26 18:41:21 +00:00
public function loadByPrimaryKey ( $mValue ) {
2016-10-06 15:57:01 +00:00
$bSuccess = $this -> loadBy ( $this -> primaryKey , $mValue );
if (( $bSuccess == true ) && method_exists ( $this , '_onLoad' )) {
$this -> _onLoad ();
}
return $bSuccess ;
}
/**
* Loads an item by it ' s recordset .
*
* @ param array $aRecordSet The recordset of the item
*/
2021-01-26 18:41:21 +00:00
public function loadByRecordSet ( array $aRecordSet ) {
$this -> values = $aRecordSet ;
2016-10-06 15:57:01 +00:00
$this -> oldPrimaryKey = $this -> values [ $this -> primaryKey ];
2021-01-26 18:41:21 +00:00
$this -> virgin = false ;
2021-08-24 18:11:10 +00:00
$this -> _setLoaded ( true );
2021-01-26 18:41:21 +00:00
self :: $_oCache -> addItem ( $this -> table . " _ " . $this -> oldPrimaryKey , $this -> values );
2016-10-06 15:57:01 +00:00
}
/**
* Function which is called whenever an item is loaded .
* Inherited classes should override this function if desired .
*
* @ return void
*/
2021-01-26 18:41:21 +00:00
protected function _onLoad () {
2016-10-06 15:57:01 +00:00
}
/**
* Gets the value of a specific field .
*
* @ param string $sField Specifies the field to retrieve
* @ return mixed Value of the field
*/
2021-01-26 18:41:21 +00:00
public function getField ( $sField ) {
2016-10-06 15:57:01 +00:00
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
return $this -> _outFilter ( $this -> values [ $sField ]);
}
/**
* Wrapper for getField ( less to type ) .
*
* @ param string $sField Specifies the field to retrieve
* @ return mixed Value of the field
*/
2021-01-26 18:41:21 +00:00
public function get ( $sField ) {
2016-10-06 15:57:01 +00:00
return $this -> getField ( $sField );
}
/**
* Sets the value of a specific field .
*
* @ param string $sField Field name
* @ param string $mValue Value to set
* @ param bool $bSafe Flag to run defined inFilter on passed value
*/
2021-01-26 18:41:21 +00:00
public function setField ( $sField , $mValue , $bSafe = true ) {
2016-10-06 15:57:01 +00:00
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
$this -> modifiedValues [ $sField ] = true ;
if ( $sField == $this -> primaryKey ) {
$this -> oldPrimaryKey = $this -> values [ $sField ];
}
if ( $bSafe == true ) {
$this -> values [ $sField ] = $this -> _inFilter ( $mValue );
} else {
$this -> values [ $sField ] = $mValue ;
}
return true ;
}
/**
* Shortcut to setField .
*
* @ param string $sField Field name
* @ param string $mValue Value to set
* @ param bool $bSafe Flag to run defined inFilter on passed value
*/
2021-01-26 18:41:21 +00:00
public function set ( $sField , $mValue , $bSafe = true ) {
2016-10-06 15:57:01 +00:00
return $this -> setField ( $sField , $mValue , $bSafe );
}
/**
* Stores the loaded and modified item to the database .
*
* @ return bool
*/
public function store () {
2021-01-26 18:41:21 +00:00
if ( ! $this -> isLoaded ()) {
2016-10-06 15:57:01 +00:00
$this -> lasterror = 'No item loaded' ;
return false ;
2021-01-26 18:41:21 +00:00
}
2016-10-06 15:57:01 +00:00
$sql = 'UPDATE `' . $this -> table . '` SET ' ;
$first = true ;
if ( ! is_array ( $this -> modifiedValues )) {
return true ;
}
foreach ( $this -> modifiedValues as $key => $bValue ) {
if ( $first == true ) {
$sql .= " ` $key ` = ' " . $this -> values [ $key ] . " ' " ;
$first = false ;
} else {
$sql .= " , ` $key ` = ' " . $this -> values [ $key ] . " ' " ;
}
}
$sql .= " WHERE " . $this -> primaryKey . " = ' " . $this -> oldPrimaryKey . " ' " ;
$this -> db -> query ( $sql );
$this -> _lastSQL = $sql ;
if ( $this -> db -> affected_rows () > 0 ) {
2021-01-26 18:41:21 +00:00
self :: $_oCache -> addItem ( $this -> table . " _ " . $this -> oldPrimaryKey , $this -> values );
2016-10-06 15:57:01 +00:00
}
return ( $this -> db -> affected_rows () < 1 ) ? false : true ;
}
/**
* Returns current item data as an assoziative array .
*
* @ return array | false
*/
2021-01-26 18:41:21 +00:00
public function toArray () {
2016-10-06 15:57:01 +00:00
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
$aReturn = array ();
foreach ( $this -> values as $field => $value ) {
$aReturn [ $field ] = $this -> getField ( $field );
}
return $aReturn ;
}
/**
* Returns current item data as an object .
*
* @ return stdClass | false
*/
2021-01-26 18:41:21 +00:00
public function toObject () {
2016-10-06 15:57:01 +00:00
$return = $this -> toArray ();
return ( false !== $return ) ? ( object ) $return : $return ;
}
/**
* Sets a custom property .
*
* @ param string $sType Specifies the type
* @ param string $sName Specifies the name
* @ param mixed $mValue Specifies the value
* @ return bool
*/
2021-01-26 18:41:21 +00:00
public function setProperty ( $sType , $sName , $mValue ) {
2016-10-06 15:57:01 +00:00
// If this object wasn't loaded before, return false
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
// Set the value
$oProperties = $this -> _getPropertiesCollectionInstance ();
$bResult = $oProperties -> setValue (
2021-01-26 18:41:21 +00:00
$this -> primaryKey , $this -> get ( $this -> primaryKey ), $sType , $sName , $mValue
2016-10-06 15:57:01 +00:00
);
return $bResult ;
}
/**
* Returns a custom property .
*
* @ param string $sType Specifies the type
* @ param string $sName Specifies the name
* @ return mixed Value of the given property or false
*/
2021-01-26 18:41:21 +00:00
public function getProperty ( $sType , $sName ) {
2016-10-06 15:57:01 +00:00
// If this object wasn't loaded before, return false
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
// Return the value
$oProperties = $this -> _getPropertiesCollectionInstance ();
$mValue = $oProperties -> getValue (
2021-01-26 18:41:21 +00:00
$this -> primaryKey , $this -> get ( $this -> primaryKey ), $sType , $sName
2016-10-06 15:57:01 +00:00
);
return $mValue ;
}
2021-01-26 18:41:21 +00:00
/**
* Deletes a custom property .
*
* @ param string $sType Specifies the type
* @ param string $sName Specifies the name
* @ return bool
*/
public function deleteProperty ( $sType , $sName ) {
2016-10-06 15:57:01 +00:00
// If this object wasn't loaded before, return false
if ( $this -> virgin == true ) {
$this -> lasterror = 'No item loaded' ;
return false ;
}
// Delete the value
$oProperties = $this -> _getPropertiesCollectionInstance ();
$bResult = $oProperties -> deleteValue (
2021-01-26 18:41:21 +00:00
$this -> primaryKey , $this -> get ( $this -> primaryKey ), $sType , $sName
2016-10-06 15:57:01 +00:00
);
return $bResult ;
}
2021-01-26 18:41:21 +00:00
/**
* Deletes a custom property by its id .
*
* @ param int $idprop Id of property
* @ return bool
*/
public function deletePropertyById ( $idprop ) {
2016-10-06 15:57:01 +00:00
$oProperties = $this -> _getPropertiesCollectionInstance ();
return $oProperties -> delete ( $idprop );
}
/**
* Deletes the current item
*
* @ return void
*/
// Method doesn't work, remove in future versions
// function delete()
// {
// $this->_collectionInstance->delete($item->get($this->primaryKey));
//}
/**
* Define the filter functions used when data is being stored or retrieved
* from the database .
*
* Examples :
* < pre >
* $obj -> setFilters ( array ( 'addslashes' ), array ( 'stripslashes' ));
* $obj -> setFilters ( array ( 'htmlencode' , 'addslashes' ), array ( 'stripslashes' , 'htmlencode' ));
* </ pre >
*
* @ param array $aInFilters Array with function names
* @ param array $aOutFilters Array with function names
*
* @ return void
*/
2021-01-26 18:41:21 +00:00
public function setFilters ( $aInFilters = array (), $aOutFilters = array ()) {
$this -> _arrInFilters = $aInFilters ;
2016-10-06 15:57:01 +00:00
$this -> _arrOutFilters = $aOutFilters ;
}
/**
* Filters the passed data using the functions defines in the _arrInFilters array .
*
2021-08-23 13:38:26 +00:00
* @ see Item :: setFilters ()
* @ param mixed $mData
* Data to filter
* @ return mixed
* Filtered data
2016-10-06 15:57:01 +00:00
*/
2021-08-23 13:38:26 +00:00
public function _inFilter ( $mData ) {
2016-10-06 15:57:01 +00:00
foreach ( $this -> _arrInFilters as $_function ) {
if ( function_exists ( $_function )) {
2021-08-23 13:38:26 +00:00
if ( is_array ( $mData )) {
foreach ( $mData as $key => $value ) {
$mData [ $key ] = $_function ( $value );
}
} else {
$mData = $_function ( $mData );
}
2016-10-06 15:57:01 +00:00
}
}
return $mData ;
}
/**
* Filters the passed data using the functions defines in the _arrOutFilters array .
*
* @ see setFilters
*
* @ param mixed $mData Data to filter
* @ return mixed Filtered data
*/
2021-08-23 13:38:26 +00:00
public function _outFilter ( $mData ) {
2021-01-26 18:41:21 +00:00
if ( is_numeric ( $mData ))
return $mData ;
2016-10-06 15:57:01 +00:00
foreach ( $this -> _arrOutFilters as $_function ) {
if ( function_exists ( $_function )) {
$mData = $_function ( $mData );
}
}
return $mData ;
}
2021-01-26 18:41:21 +00:00
protected function _setMetaObject ( $sObjectName ) {
2016-10-06 15:57:01 +00:00
$this -> _metaObject = $sObjectName ;
}
2021-01-26 18:41:21 +00:00
public function getMetaObject () {
2016-10-06 15:57:01 +00:00
global $_metaObjectCache ;
if ( ! is_array ( $_metaObjectCache )) {
$_metaObjectCache = array ();
}
$sClassName = $this -> _metaObject ;
$qclassname = strtolower ( $sClassName );
if ( array_key_exists ( $qclassname , $_metaObjectCache )) {
if ( is_object ( $_metaObjectCache [ $qclassname ])) {
if ( strtolower ( get_class ( $_metaObjectCache [ $qclassname ])) == $qclassname ) {
$_metaObjectCache [ $qclassname ] -> setPayloadObject ( $this );
return $_metaObjectCache [ $qclassname ];
}
}
}
if ( class_exists ( $sClassName )) {
2021-01-26 18:41:21 +00:00
$_metaObjectCache [ $qclassname ] = new $sClassName ( $this );
2016-10-06 15:57:01 +00:00
return $_metaObjectCache [ $qclassname ];
}
}
2021-08-23 13:38:26 +00:00
/**
* Resets class variables back to default
* This is handy in case a new item is tried to be loaded into this class instance .
*/
protected function _resetItem () {
parent :: _resetItem ();
2016-10-06 15:57:01 +00:00
2021-08-23 13:38:26 +00:00
// make sure not to reset filters because then default filters would always be used for loading
$this -> values = null ;
$this -> modifiedValues = null ;
$this -> _metaObject = null ;
$this -> _lastSQL = null ;
}
2016-10-06 15:57:01 +00:00
}