Documentation (together with my other libs)
<?php
// --- INCLUDES --- //
require_once dirname(__FILE__).'/'.'inc.php4';
require_once dirname(__FILE__).'/'.'lib.cDBAccess_MySQL.php4';
// Event Logging
require_once dirname(__FILE__).'/'.'lib.cApp.php';
require_once dirname(__FILE__).'/'.'lib.cLog.php';
require_once dirname(__FILE__).'/'.'lib.cObjectPersistence_ColumnTypes.php';
// --- CONSTANTS --- //
// Column types
define('DWOP_TYPE_STR', 1);
define('DWOP_TYPE_NUM', 2);
define('DWOP_TYPE_REAL', 3);
define('DWOP_TYPE_BOOL', 4);
define('DWOP_TYPE_ENUM', 5);
define('DWOP_TYPE_SET', 6);
// Column flags
define('DWOP_NOT_NULL', 1);
define('DWOP_BINARY', 2);
//define('DWOP_BINARY', 2);
// For cDwOpClass::GetObjectMultiIdString()
define('DWOP_VALUE_DUMP_MODE__SQL', 0);
define('DWOP_VALUE_DUMP_MODE__SQL_SHORT', 2);
define('DWOP_VALUE_DUMP_MODE__SQL_VALUES', 3);
define('DWOP_VALUE_DUMP_MODE__ESCAPED_VALUES', 4);
define('DWOP_VALUE_DUMP_MODE__COMA', 5);
/** *********************************************************************************
<h1> RDBMS Object Loader for PHP </h1>
@version 2.4.6
@author Ondra Zizka, Dynawest; ondra@dynawest.cz
<h2>Plan:</h2>
3.0.0:
- Add: Complete cross-class references handling
2.x.x:
- Class::RemProperty() - handle removal of ID and KEY properties.
Class::aoIdProperties - rewrite so that GetIdProperties etc will compute from properties themselves. ??? Good idea???
<h2>History:</h2>
2.4.7:
- Fixed: cDwOpProperty::FormatForSql() returns correctly for DWOP_TYPE_REAL column types.
2.4.7:
- Added: DeleteObject() supports multi-property PRIMARY KEYS in it's second parameter
2.4.6:
- Added: Object Pool supports multi-property PRIMARY KEYS
2.4.5:
- Fixed: Fix in SaveObject() - now saves all properties that are set. Null values for NOT NULL columns converted to default.
- Added: function GetNonKeyProperties()
- Added: DeleteObject() now can take Class name and single ID as parameters.
- Added: cDwOpProperty now remembers it's PRIMARY KEY properties added through AddIdProperty() etc.
- Added: cDwOpProperty::IsKey()
- Changed: cDwOpColumnType::GetDefaultDefault() is not abstract returns a value according to basic column type.
- Fixed: DwFwIdAndProperties::HasProperty() now uses array_key_exists() instead of fucking isset().
2.4.4:
- Fixed: Massive fix in SaveObject() and one in DeleteObject()
- Added: param $sGlue to GetIdPropertiesSql($oObject, $sGlue=', ')
2.4.3:
- Added: Support for multi-property PRIMARY KEYs in SaveObject(), DeleteObject()
2.4.2:
- Added: DeleteObject($oObject);
- Added: GetIdPropertiesSql()
2.4.1:
- Added: param $bOverwrite to function AddObjectIntoPool( $oObject, $bOverwrite=true )
2.4.0:
- Added: M : N cross-class references
- Added: function SetMnRelation($oClass1, $oClassGlue, $oClass2)
- Added: function LoadObjectsByMnRelation($oObject, $oClassGlue, $oClass2, $xId=null)
- Added: Support for multi-property PRIMARY key - but only for keeping it, not for loading or saving
- Added: Real column types
(abstract class cDwOpColumnType_Real extends cDwOpColumnType) and derived classes)
- Added: Ordinal column types can take possible values definiton as they go from the DB:
"'value', 'value', ..."
- Added: Column types BIGINT and MEDIUMINT
Objects loading:
- Added: function LoadObjects($oClass)
- Added: function LoadObjectsBySql($xClass, $sSQL)
- Added: function LoadObjectsFromResult($xClass, $oRes)
Class related:
- Added: function ConvertAndCheckClass( $oClass )
- Added: function CreateClassCopy( $sName, $xClass )
- Added: function CreateClassByTable( $sName, $sTable )
- Added: function CreateColumnTypeObject($sTypeString, $bNull, $sDefault)
2.3.0:
- Added: CreateClassByTable()
Creates class definition according to a table in a database.
2.2.1:
- Added: LoadObjectsFromResult().
- Changed: LoadObjectsByValue() now uses LoadObjectsFromResult().
2.2.0:
- Added: Ordering by properties support.
GetOrderProperties(), SetOrderProperties()
2.1.0:
- Added: Default values, better checking.
GetDefault(), SetDefault(), GetDefaultDefault()
2.0.2:
- Added: Load* functions' first parameter can be also a class name string.
2.0.1:
- Added: GetPoolCount()
- Changed: SaveObject() adds UPDATEd (overwrite) and INSERTed objects into pool
2.0.0:
- Add central object registry - object is loaded only once,
then return the formerly loaded
1.1.0:
- Added support for AUTO_INCREMENT when creating objects.
- Added possibility to load objects by values.
***********************************************************************************/
class cDwObjectPersistence_DB {
var $oDB = null;
function &GetDB() { return $this->oDB; }
var $sError = null;
function GetError() { return $this->sError; }
function SetError($sError){ $this->sError = $sError; }
function cDwObjectPersistence_DB($oDB){
$this->oDB = $oDB;
}
/**<***********************************************************************>
* Class objects dictionary *
***************************************************************************/
var $aoClassesDictionary = Array();
function GetClassNames(){ return array_keys($this->aoClassesDictionary); }
function AddClassIntoDictionary( $oClass ){
$this->aoClassesDictionary[$oClass->GetName()] = $oClass;
}
function GetClassFromDictionary( $sClassName ){
return isset($this->aoClassesDictionary[$sClassName]) ? $this->aoClassesDictionary[$sClassName] : null;
}
/**<***********************************************************************>
* Objects pool *
***************************************************************************/
var $aaoObjectPool = Array();
function AddObjectIntoPool( $oObject, $bOverwrite=true ){
if( !is_object($oObject) ) return false;
$sClassName = get_class($oObject);
//App::Log("\$sClassName: ".$sClassName);///
if( !$oClass = $this->GetClassFromDictionary($sClassName) ){ return false; }
// Get the object unique PRIMARY KEYs string
//App::Log("GetIdPropertiesCount(): ".$oClass->GetIdPropertiesCount());///
switch( $oClass->GetIdPropertiesCount() ){
case 0: $bUsePool = false; return false; break;
case 1: $xId = $oObject->GetId(); break;
default: $xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES ); break;
}
//if( 0 == $oClass->GetIdPropertiesCount() ) return false;
//$xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES );
// If we should not overwrite...
if( !$bOverwrite ){
// and the object exists, don't write and return true.
if( isset( $this->aaoObjectPool[get_class($oObject)][$xId] ) )
return true;
}
// Save the object handle.
$this->aaoObjectPool[get_class($oObject)][$xId] = $oObject;
return true;
}
function AddObjectIntoPool_SingleId( $oObject, $bOverwrite=true ){
if( !is_object($oObject) ) return false;
// If we should not overwrite...
if( !$bOverwrite ){
// and the object exists, don't write and return true.
if( isset( $this->aaoObjectPool[get_class($oObject)][$oObject->GetId()] ) )
return true;
}
// Save the object handle.
$this->aaoObjectPool[get_class($oObject)][$oObject->GetId()] = $oObject;
return true;
}
function GetObjectFromPool( $sClassName, $xId ){
$oObject = null;
if( isset($this->aaoObjectPool[$sClassName][$xId]) ){
$oObject = $this->aaoObjectPool[$sClassName][$xId];
//echo "<pre><strong>Pool hit!</strong></pre>";///
}
return $oObject;
}
function RemObjectFromPool( $oObject ){
if( !is_object($oObject) ) return false;
// Get the Class object
$sClassName = get_class($oObject);
if( !($oClass = $this->GetClassFromDictionary($sClassName)) ){ return false; }
// Get the object unique PRIMARY KEYs string
//App::Log("GetIdPropertiesCount(): ".$oClass->GetIdPropertiesCount());///
switch( $oClass->GetIdPropertiesCount() ){
case 0: $bUsePool = false; return false; break;
case 1: $xId = $oObject->GetId(); break;
default: $xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES ); break;
}
// Remove the object with the acquired ID
if( isset( $this->aaoObjectPool[$sClassName][$xId] ) )
unset($this->aaoObjectPool[$sClassName][$xId]);
return true;
}
function RemObjectFromPool_SingleId( $oObject ){
if( !is_object($oObject) ) return false;
$sClassName = get_class($oObject);
$xId = $oObject->GetId();
if( isset( $this->aaoObjectPool[$sClassName][$xId] ) )
unset($this->aaoObjectPool[$sClassName][$xId]);
return true;
}
function HasObjectInPool( $oObject ){
if( !is_object($oObject) ) return false;
// Get the Class object
$sClassName = get_class($oObject);
if( !($oClass = $this->GetClassFromDictionary($sClassName)) ){ return false; }
// Get the object unique PRIMARY KEYs string
switch( $oClass->GetIdPropertiesCount() ){
case 0: $bUsePool = false; break;
case 1: $xId = $oObject->GetId(); break;
default: $xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES ); break;
}
// $xId = $oObject->GetId();
$xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES );
if( isset( $this->aaoObjectPool[get_class($oObject)][$xId] ) )
return true;
return false;
}
function HasObjectInPool_SingleId( $oObject ){
if( !is_object($oObject) ) return false;
$xId = $oObject->GetId();
if( isset( $this->aaoObjectPool[get_class($oObject)][$xId] ) )
return true;
return false;
}
function GetPoolCount(){
return array_sum(array_map('Count', $this->aaoObjectPool));
}
/**<***********************************************************************>
* Converts the class name to the DwOpClass object and checks the class. *
***************************************************************************/
function ConvertAndCheckClass( $oClass ){
// $oClass can be either cDwOpClass object or a class name
if( !$oClass ){ $this->SetError("Bad param (null) \$oClass for ".__METHOD__." in ".CallInfo(-2)); return false; }
// A string - try to find the Class in the Dictionary
if( is_string($oClass) ){
$sClassName = $oClass;
$oClass = $this->GetClassFromDictionary($sClassName);
if( !is_object($oClass) ){ $this->SetError("Class [$sClassName] not found in dictionary."); return false; }
}
// Not a string - either the Class object or an object of some Class.
else{
if( !is_object($oClass) ){ $this->SetError("Bad param (not string or object) \$oClass for ".__METHOD__." in ".CallInfo(-2)); return false; }
if( $oClass instanceof cDwOpClass ){
$sClassName = $oClass->GetName();
}else{
// object of some Class - try to find the Class object.
$sClassName = get_class($oClass);
$oClass = $this->GetClassFromDictionary( $sClassName );
if( !is_object($oClass) ){ $this->SetError("Object's Class [$sClassName] not found in dictionary."); return false; }
}
}
// Check class existence
if( !class_exists($sClassName) ){ $this->SetError("Non-existent PHP class [$sClassName]. in ".__METHOD__." in ".CallInfo(-2)); return false; }
return $oClass;
}
/**<***********************************************************************>
* Deletes an object with ID $iID of the given class $oClass *
Deletes the given object from the DB.
***************************************************************************/
function DeleteObject($oObject, $xId=null){
//echo "<pre>\n class object: ".AdjustedPrintR($oClass)."</pre>";///
//if( !is_object( $oObject ) ) return false;
$bSucc = false;
do{
/*// Find the Class object in the Dictionary
$sClassName = get_class($oObject);
do{
$oClass = $this->GetClassFromDictionary($sClassName);
$sClassName = get_parent_class($sClassName);
}while( $sClassName && !$oClass );
// Check class object //
//if( !$oClass ){ $this->SetError("Class [$sClassName] not found in the dictionary in ".__METHOD__." @ ".__LINE__); break; }
/*/
if( !($oClass = $this->ConvertAndCheckClass($oObject)) ){ $this->SetError("!\$oClass in ".__METHOD__." @ ".__LINE__); break; }
$sClassName = $oClass->GetName();
/**/
// If $oObject is an instance of Class, get it's ID.
// If $oObject was just identification of a Class, create a temporary object with just IDs.
if( !($oObject instanceof $sClassName) ){
// Check the ID - false, null, or empty array? -> fail.
if( !$xId ){ $this->SetError("Unknown object ID to delete in ".__METHOD__." @ ".__LINE__); break; }
// If $xId is multiple ID - associative array of ids
if( is_array($xId) ){
$oObject = new $sClassName();
foreach( $xId as $k => $v )
$oObject->SetProperty($k, $v);
}
// Single ID
else{
//$oObject = $this->LoadObjectById($oClass, $xId);
//if(!$oObject) { $this->SetError("!LoadObjectById(".$oClass->GetName().", $xId) in ".__METHOD__." @ ".__LINE__); break; }
$oObject = new $sClassName();
$oObject->SetId($xId);
}
}
// -- From here further, we have DwOpClass $oClass and it's (pseudo)instance $oObject. -- //
// Remove from the Object Pool
if( !$this->RemObjectFromPool($oObject) ){ $this->SetError("!RemObjectFromPool() in ".__METHOD__." @ ".__LINE__); }
$sTable = $oClass->GetTable();
/*/ For one ID (PRIMARY KEY) property only...
$oIdProp = $oClass->GetIdProperty();
$sColId = $oIdProp->GetColName();
$xId = $oIdProp->FormatForSql( $oObject->GetProperty($oIdProp->GetColName()) );
$sSQL = "DELETE FROM $sTable WHERE $sColId = $xId";
/*/
// For all PRIMARY KEYs:
$saxIdsCond = $oClass->GetIdPropertiesSql($oObject, ' AND ');
$sSQL = "DELETE FROM $sTable WHERE $saxIdsCond";
/**/
// Perform SQL query
$oRes = $this->GetDB()->Execute($sSQL);
if( !$oRes || !$oRes->IsOK() ){ $this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]"); break; }
$bSucc = true;
}while(false);
return $bSucc;
}// cDwObjectPersistence_DB::DeleteObject()
/**<*********************************************************************************>
* Deletes objects of the given class $oClass
* with some property equal to the given value.
@param oClass: cDwOpClass object or a class name to find in dictionary.
@param sPropertyName: Name of the property to compare with $xVal.
@param xVal: Value to compare property with.
@returns array of objects with value $sPropertyName equal to $xVal.
*************************************************************************************/
function DeleteObjectsByValueBad($oClass, $sPropertyName, $xVal){
//echo "<pre>\n class object: ".AdjustedPrintR($oClass)."</pre>";///
if( !( $oClass = $this->ConvertAndCheckClass($oClass) ) ) return false;
$sClassName = $oClass->GetName();
// Get the property by which to recognize the object to load
$oProp = $oClass->GetProperty($sPropertyName);
if( null == $oProp ){ $this->SetError("No such property in class [$sClassName]: [$sPropertyName]"); return false; }
// Create SQL query
$sTable = $oClass->GetTable();
$sCol = $oProp->GetColName();
$oIdProp = $oClass->GetIdProperty();
$sColId = $oIdProp->GetColName();
$sOrderSql = $oClass->GetOrderPropertiesSql(); // ORDER BY part
$sSQL = "DELETE FROM $sTable WHERE $sCol = ".$oProp->FormatForSql($xVal)." ".$sOrderSql;
// Perform SQL query
$oRes = $this->GetDB()->Execute($sSQL);
if( !$oRes || !$oRes->IsOK() ){ $this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL] in ".__METHOD__.' @ '.__LINE__); return false; }
// TODO: Remove objects from Object Pool!
$this->RemObjectFromPool($oObject);
return true;
}// LoadObjectsByValue($oClass, $sPropertyName, $xVal)
/**<***********************************************************************>
* Second version *
***************************************************************************/
function DeleteObjectsByValue($oClass, $sPropertyName, $xVal){
$aoObjects = $this->LoadObjectsByValue($oClass, $sPropertyName, $xVal);
if(!is_array($aoObjects)) return false;
foreach( $aoObjects as $oObject){
$this->DeleteObject($oObject);
}
return true;
}// LoadObjectsByValue($oClass, $sPropertyName, $xVal)
/**<***********************************************************************>
* Loads an object with ID $iID of the given class $oClass *
***************************************************************************/
function LoadObjectById($oClass, $iID){
//echo "<pre>\n class object: ".AdjustedPrintR($oClass)."</pre>";///
/*/ First parameter can be either cDwOpClass object or a class name
if( is_string($oClass) ){
$sClassName = $oClass;
$oClass = $this->GetClassFromDictionary($sClassName);
if( !$oClass ) return false;
}else{
$sClassName = $oClass->GetName();
}
// Check class existence
if( !class_exists($sClassName) )
return false;
/*/
if( !( $oClass = $this->ConvertAndCheckClass( $oClass ) ) ) return false;
$sClassName = $oClass->GetName();/**/
// Look for the object in the pool
if( $oObject = $this->GetObjectFromPool($sClassName, $iID) )
return $oObject;
$sTable = $oClass->GetTable();
$oIdProp = $oClass->GetIdProperty();
$sColId = $oIdProp->GetColName();
// Create and perform SQL query
$sSQL = "SELECT * FROM $sTable WHERE $sColId = ".$oIdProp->FormatForSql($iID);
$oRet = $this->GetDB()->Select($sSQL);
if( !$oRet->IsOK() ) return false;
if( 0 == $oRet->NumRows() ) return null;
$aData = $oRet->FetchRow(MYSQL_ASSOC);
// Create the object
$oObject = new $sClassName();
// Load all declared properties
foreach( $oClass->GetProperties() as $oProperty ){
//echo "<div>\$oObject->SetProperty( ".$oProperty->GetColName().", \$aData[".$oProperty->GetColName()."] );</div>";///
$oObject->SetProperty( $oProperty->GetColName(), $oProperty->GetColType()->ConvertFromResult( $aData[$oProperty->GetColName()] ) );
}
$this->AddObjectIntoPool($oObject);
return $oObject;
}// LoadObjectById($oClass, $iID)
/**<***********************************************************************************>
* Loads all objects of the given class $oClass.
@param oClass: cDwOpClass object or a class name to find in dictionary.
@returns array of objects of the specified class.
***************************************************************************************/
function LoadObjects($oClass){
/*/ First parameter can be either cDwOpClass object or a class name
if( is_string($oClass) ){
$sClassName = $oClass;
$oClass = $this->GetClassFromDictionary($sClassName);
if( !is_object($oClass) ){ $this->SetError("Class [$sClassName] not found in dictionary."); return false; }
}else{
$sClassName = $oClass->GetName();
}
// Check class existence
if( !class_exists($sClassName) ){ $this->SetError("Non-existent class [$sClassName]."); return false; }
/*/
if( !( $oClass = $this->ConvertAndCheckClass( $oClass ) ) ) return false;
$sClassName = $oClass->GetName();/**/
// Create SQL query
$sTable = $oClass->GetTable();
$sOrderSql = $oClass->GetOrderPropertiesSql(); // ORDER BY part
$sSQL = "SELECT * FROM $sTable ".$sOrderSql;
// Perform SQL query
$oRes = $this->GetDB()->Select($sSQL);
if( !$oRes || !$oRes->IsOK() ){
$this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]");
return false;
}
// Load Objects
$aoObjects = $this->LoadObjectsFromResult($oClass, $oRes);
$oRes->FreeResult();
return $aoObjects;
}// cDwObjectPersistence_DB::LoadObjects()
/**<*********************************************************************************>
* Loads an objects of the given class $oClass
* with some property equal to the given value.
@param oClass: cDwOpClass object or a class name to find in dictionary.
@param sPropertyName: Name of the property to compare with $xVal.
@param xVal: Value to compare property with.
@returns array of objects with value $sPropertyName equal to $xVal.
*************************************************************************************/
function LoadObjectsByValue($oClass, $sPropertyName, $xVal){
//echo "<pre>\n class object: ".AdjustedPrintR($oClass)."</pre>";///
/*/ First parameter can be either cDwOpClass object or a class name
if( is_string($oClass) ){
$sClassName = $oClass;
$oClass = $this->GetClassFromDictionary($sClassName);
if( !is_object($oClass) ){
$this->SetError("Class [$sClassName] not found in dictionary.");
return false;
}
}else{
$sClassName = $oClass->GetName();
}
// Check class existence
if( !class_exists($sClassName) ){ $this->SetError("Non-existent class [$sClassName]."); return false; }
/*/
if( !( $oClass = $this->ConvertAndCheckClass( $oClass ) ) ) return false;
$sClassName = $oClass->GetName();/**/
// Get the property by which to recognize the object to load
$oProp = $oClass->GetProperty($sPropertyName);
if( null == $oProp ){
$this->SetError("No such property in class [$sClassName]: [$sPropertyName]");
return false;
}
// Create SQL query
$sTable = $oClass->GetTable();
$sCol = $oProp->GetColName();
$oIdProp = $oClass->GetIdProperty();
$sColId = $oIdProp->GetColName();
$sOrderSql = $oClass->GetOrderPropertiesSql(); // ORDER BY part
$sSQL = "SELECT * FROM $sTable WHERE $sCol = ".$oProp->FormatForSql($xVal)." ".$sOrderSql;
/*// Perform SQL query
$oRes = $this->GetDB()->Select($sSQL);
if( !$oRes || !$oRes->IsOK() ){
$this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]");
return false;
}
// Load Objects
$aoObjects = $this->LoadObjectsFromResult($oClass, $oRes);
$oRes->FreeResult();/*/
$aoObjects = $this->LoadObjectsBySql($oClass, $sSQL);/**/
return $aoObjects;
}// LoadObjectsByValue($oClass, $sPropertyName, $xVal)
/**<*********************************************************************************>
* Performs SQL query and converts the result to an array of objects. *
*************************************************************************************/
function LoadObjectsBySql($xClass, $sSQL){
// Perform SQL query
$oRes = $this->GetDB()->Select($sSQL);
if( !$oRes || !$oRes->IsOK() ){
$this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]");
return false;
}
// Load Objects
$aoObjects = $this->LoadObjectsFromResult($xClass, $oRes);
$oRes->FreeResult();
return $aoObjects;
}
/**<*********************************************************************************>
* Converts the result to an array of objects. *
*************************************************************************************/
function LoadObjectsFromResult($xClass, $oRes){
// Convert and check the class
if( !( $oClass = $this->ConvertAndCheckClass( $xClass ) ) ){
$this->SetError("!ConvertAndCheckClass(".gettype($xClass)."): ".$this->GetError()); return false;
}
$sClassName = $oClass->GetName();
$aoObjects = Array();
//if( 0 == $oRes->NumRows() ) return $aoObjects;
// Class Name
//if( !is_object($oClass) ) echo CallInfo(-2);
$aoPropertiesToTraverse = Array();
// Get the list of the properties that will be set from the result.
// Check column existence for all declared properties
$aoFields = $oRes->GetColumns();
$absFieldsContained = Array();
foreach( $aoFields as $oField ){ $absFieldsContained[$oField->name] = 1; }
//App::Log("\$absFieldsContained: ".AdjustedPrintR($absFieldsContained));///
foreach( $oClass->GetProperties() as $oProperty ){
$sColName = $oProperty->GetColName();
if( !array_key_exists($sColName, $absFieldsContained) ){
$this->SetError("Warn: Column [$sColName] for property [".$oProperty->GetName()."] is not set; in ".__METHOD__." in ".CallInfo(-2));
App::Log("Warn: Column [$sColName] for property [".$oProperty->GetName()."] is not set; in ".__METHOD__); continue;
}
$aoPropertiesToTraverse[] = $oProperty;
}/**/
// Create the objects. For each row:
while( $aData = $oRes->FetchRow(MYSQL_ASSOC) ){
$oObject = new $sClassName();
/*// Load all declared properties
foreach( $oClass->GetProperties() as $oProperty ){
//echo "<div>\$oObject->SetProperty( ".$oProperty->GetColName().", \$aData[".$oProperty->GetColName()."] );</div>";///
$sColName = $oProperty->GetColName();
//if( !isset( $aData[$sColName] ) && !is_null($aData[$sColName]) ){
if( !array_key_exists($sColName, $aData) ){
App::Log("Warn: Column [$sColName] for property [".$oProperty->GetName()."] is not set."); continue;
} // DONE: Move before the while - fetch_fields()
$oObject->SetProperty( $oProperty->GetColName(), $aData[$sColName] );
}/**/
// Load properties that are present in the result
foreach( $aoPropertiesToTraverse as $oProperty ){
//echo "<div>\$oObject->SetProperty( ".$oProperty->GetColName().", \$aData[".$oProperty->GetColName()."] );</div>";///
$sColName = $oProperty->GetColName();
$oObject->SetProperty( $sColName, $oProperty->GetColType()->ConvertFromResult($aData[$sColName]) );
}
// Get object's unique ID, if possible
$bUsePool = true;
//App::Log("GetIdPropertiesCount(): ".$oClass->GetIdPropertiesCount());///
switch( $oClass->GetIdPropertiesCount() ){
case 0: $bUsePool = false; break;
case 1: $xId = $oObject->GetId(); break;
default: $xId = $oClass->GetObjectMultiIdString( $oObject, DWOP_VALUE_DUMP_MODE__SQL_VALUES ); break;
}
// Look for the object in the pool
if(!$bUsePool)
$aoObjects[] = $oObject;
else
if( $oObjectFromPool = $this->GetObjectFromPool($sClassName, $xId) ){
//App::Log("Pool hit [$sClassName, ".$xId."]");///
$aoObjects[] = $oObjectFromPool;
}else{
//App::Log("Pool miss [$sClassName, ".$xId."]");///
$aoObjects[] = $oObject;
$this->AddObjectIntoPool($oObject);
}
}// while( for each row in result )
return $aoObjects;
}// cDwObjectPersistence::LoadObjectsFromResult($oClass, $oRes)
/**<***********************************************************************>
* Saves an object with ID $iID of the given class $oClass *
***************************************************************************/
function SaveObject($oObject){
//echo "<pre>\n class object: ".AdjustedPrintR($oClass)."</pre>";///
//App::Log("Object: ".AdjustedPrintR($oObject));///
if( !is_object( $oObject ) ) return false;
// Whether to try UPDATE first before INSERT
$bDoUpdate = true;
$bZeroUpdatedRows = false;
// Add this Class object into the dictionary
// Get the Class object - for this PHP class or some ancestor class
$sClassName = get_class($oObject);
do{
$oClass = $this->GetClassFromDictionary($sClassName);
$sClassName = get_parent_class($sClassName);
}while( $sClassName && !$oClass );
// Check class object //
if( !$oClass )
return false;
$sTable = $oClass->GetTable();
/// --- PRIMARY KEYS --- ///
/*/ For one ID (PRIMARY KEY) property only...
$oIdProp = $oClass->GetIdProperty(); //x Single-ID way
$sColId = $oIdProp->GetColName(); //x Single-ID way
$iID = $oObject->GetProperty( $oIdProp->GetColName() );
$sIdForSql = $oIdProp->FormatForSql($iID); //x Single-ID way
/*/
// For all PRIMARY KEYs:
$saxIds = $oClass->GetIdPropertiesSql( $oObject );
$saxIdsCond = $oClass->GetIdPropertiesSql( $oObject, ' AND ' );
/**/
/// --- VALUES --- ///
// Store all declared properties - create the SQL part
$asSqlParts = Array();
$aoIdProps = $oClass->GetIdProperties();
foreach( $oClass->GetProperties() as $oProperty ){
//echo "<div>\$oObject->GetProperty( ".$oProperty->GetColName()." );</div>";///
$bPropertySet = $oObject->HasProperty( $oProperty->GetName() );
//App::Log("HasProperty(".$oProperty->GetName().") ? : ".(int)$oObject->HasProperty($oProperty->GetName()) );///
// Check whether PRIMARY KEY properties are set and skip them.
//if( $oProperty == $oIdProp ) continue;
//if( $oProperty->IsIdProperty() ) continue;
if( in_array($oProperty, $aoIdProps) ){
// Multi-property PRIMARY key and some is not set -> error
if( !$bPropertySet && 1 < Count($aoIdProps) ){
$this->SetError("Multi-property PRIMARY - property [".$oProperty->GetName()."] not set! in ".__METHOD__." @ ".__LINE__);
//App::Log("Error!");///
return false;
}
// Skip ID column(s) - we don't want to set them as other properties
//App::Log("Skipping ID col [".$oProperty->GetName()."]");///
continue;
}
// Skip undefined properties - or set them to DEFAULT ??? -> TODO
if( !$bPropertySet ){
//$xVal = $oProperty->GetDefault();
continue;
}
//App::Log("Adding col [".$oProperty->GetName()."]");///
$sPropColName = $oProperty->GetColName();
$xVal = $oObject->GetProperty( $sPropColName );
//if( $sPropColName == 'targeting_fee' ) App::Log("FDG: (".gettype($xVal).") $xVal, ".AdjustedPrintR($oProperty));///
if( null === $xVal && !$oProperty->GetColType()->IsNull() )
$xVal = $oProperty->GetColType()->GetDefault();
$asSqlParts[] = $sPropColName.'='.$oProperty->FormatForSql($xVal);
}
$saParts = implode(', ', $asSqlParts);
//App::Log("\$saParts: ".$saParts);///
// Multiple KEY and nothing set - error (we do not INSERT unset multi-column rows )
// So other way: Don't try UPDATE if no other property set.
if( 0 == Count($asSqlParts) && 1 < Count($aoIdProps) ){
//$this->SetError("Multiple KEY and no normal properties set. in ".__METHOD__." @ ".__LINE__);); return false;
$bDoUpdate = false;
$bZeroUpdatedRows = true;
}
// Whether to add the object into the Object Pool.
// Generally, add if the object was created; don't overwrite we are only saving existing object.
$bAddObjectIntoPool = true;
$bOverwriteObjectInPool = false;
// If we are saving single-prop PRIMARY KEYed object and it is set to null, we should inser new.
//App::Log("ID: (".gettype($oObject->GetId()).") ".$oObject->GetId());///
if( 1 == $oClass->GetIdPropertiesCount() && (null === $oObject->GetId()) ){
$bDoUpdate = false;
}
// Multi-property PRIMARY key and some is not set -> error
//if( 1 < $oClass->GetIdPropertiesCount() ){ } // Done above
// UPDATE
//if( null !== $oObject->GetId() )
if( $bDoUpdate ){
// Create SQL query
//$sSQL = "UPDATE $sTable SET %s WHERE $sColId = ".$sIdForSql; //x Single-ID way
$sSQL = "UPDATE $sTable SET %s WHERE $saxIdsCond";
$sSQL = sprintf($sSQL, $saParts );
//echo "<div>$sSQL</div>";///
// Perform SQL query
$oRet = $this->GetDB()->Execute($sSQL);
//echo $oRet->GetError();///
if( !($oRet->IsOK()) ){ $this->SetError($oRet->GetError()); return false; }
if( 0 < $oRet->NumRows() ){
$this->AddObjectIntoPool( $oObject );
return true;
}
$bZeroUpdatedRows = true;
/*// If commented, tries to INSERT. If not, checks here for the row existence first.
// No rows affected - did we UPDATE with no changes, or the row was not found?
$sSQL = "SELECT COUNT(*) FROM $sTable WHERE $sColId = ".$sIdForSql;
//$oRet = $this->GetDB()->Execute($sSQL);
//if( !($oRet->IsOK()) ){ $this->SetError($oRet->GetError()); return false; }
//if( 0 != $oRet->GetCell(0,0) ){
$sVal = $oRet->SelectCell($sSQL, 0,0);
if( null === $sVal ){ $this->SetError("Error in SelectCell: [$sSQL]"); return false; }
if( 0 != $oRet->GetCell(0,0) ){
$this->AddObjectIntoPool( $oObject );
return true;
}/**/
}
// Row with ID not found or object ID is NULL -> INSERT
do{
//$sSQL = "INSERT INTO $sTable SET $sColId = $sIdForSql, ".$saParts;
$sSQL = "INSERT INTO $sTable SET $saxIds ";
if( $saParts ) $sSQL .= ", ".$saParts;
//echo "<div>$sSQL</div>";///
// Perform SQL query
//echo "\nSelectMode: ".(int)$this->GetDB()->GetSelectMode();///
$oRet = $this->GetDB()->Execute($sSQL);
// If we did UPDATE with no changes,
if($bZeroUpdatedRows){
// And this insert caused error 1062, then it's OK - the row just existed before.
if( !$oRet || (!$oRet->IsOK() && $oRet->GetErrno() == 1062 ) ){
break;
}
}
/*/ Other way:
// If INSERT caused an error:
if( !$oRet || !$oRet->IsOK() ){
// If we did not UPDATE with no changes OR the error is DUPLICATE ENTRY
if(!$bZeroUpdatedRows || ( !$oRet || $oRet->GetErrno() == 1062 ) )
$this->SetError("INSERT failed. ".($oRet ? '['.$oRet->GetError().']' : '')); return false;
}/* Too complex */
if( 0 == $oRet->NumRows() ){ $this->SetError("INSERT affected no rows. SQL: [".$sSQL."] Errno: ".$oRet->GetErrno()); return false; }
$oObject->SetId( $this->GetDB()->GetLastInsertId() );
// We created a new object, thus if any of the same ID is in the pool, overwrite.
$bOverwriteObjectInPool = true;
}while(false);
// If asked, put object into the bool. If already there, it's overwritten.
if( $bAddObjectIntoPool )
$this->AddObjectIntoPool( $oObject, $bOverwriteObjectInPool );
return true;
}// LoadObjectById($oClass, $iID)
/**<***********************************************************************>
* Creates a cDwOpClass object copy. *
***************************************************************************/
function CreateClassCopy( $sName, $xClass ){
// The second parameter can be either cDwOpClass object or a class name
if( is_string($xClass) ){
$sClassName = $xClass;
$xClass = $this->GetClassFromDictionary($sClassName);
if( !is_object($xClass) ){
$this->SetError("Class [$sClassName] not found in dictionary.");
return false;
}
}else{
$sClassName = $xClass->GetName();
}
// Make a copy
$oClass = clone $xClass;
$oClass->SetName( $sName );
$this->AddClassIntoDictionary($oClass);
return $oClass;
}
/**<***********************************************************************>
* Creates a cDwOpClass using it's definition from database. *
***************************************************************************/
function CreateClassByTable( $sName, $sTable ){
do{
$oClass = new cDwOpClass( $sName, $sTable );
// Load columns info
$sSQL = "SHOW COLUMNS FROM $sTable";
$oRes = $this->GetDB()->Select($sSQL);
if( !$oRes || !$oRes->IsOK() ){ $this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]"); return null; }
// For each row (which represent columns in the table)
while( $a = $oRes->FetchRow(MYSQL_ASSOC) ){
$oColObject = $this->CreateColumnTypeObject( $a['Type'], $a['Null']=='YES', $a['Default'] );
if( null === $oColObject ){
$this->SetError("Table column [$sTable.".$a['Field']."]: ".$this->GetError()." in ".__METHOD__." @ ".__LINE__);
//App::Log($this->GetError());///
$oClass = null; break;
}
$oProp = $oClass->AddProperty($a['Field'], $oColObject );
$oProp->SetNull($a['Null']=='YES');
if( 'PRI' == $a['Key'] ){ $oClass->AddIdProperty($oProp); }
$oProp->SetUnique( 'PRI' == $a['Key'] || 'UNI' == $a['Key'] );
}
$oRes->FreeResult();
if($oClass)
$this->AddClassIntoDictionary($oClass);
}while(false);
return $oClass;
}
//$oClass = $oOP->ExtendClassByTable('cAdplazeAdPage_Coupon', 'cAdplazeAdPage', 'ap_adpages_coupons');/**/
/**<***********************************************************************>
* Extends an existings cDwOpClass with columns from a table. *
***************************************************************************/
function ExtendClassByTable($sClassNameNew, $sClassNameOld, $sTable){
// Old Class object
$oClassOld = $this->ConvertAndCheckClass($sClassNameOld);
if(!$oClassOld){ $this->SetError("!ConvertAndCheckClass($sClassNameOld)"); return null; }
$sClassNameOld = $oClassOld->GetName();
$aoOldIdProps = $oClassOld->GetIdProperties();
//$oClass = $this->CreateClassCopy($sClassNameNew, $sClassNameOld);
//$oClass = $this->CreateClassByTable($sClassNameNew, $sTable);
$oClass = new cDwOpClass( $sClassNameNew, $sTable );
$oClass->_SetParentClass( $oClassOld );
// Load columns info
$sSQL = "SHOW COLUMNS FROM $sTable";
$oRes = $this->GetDB()->Select($sSQL);
if( !$oRes || !$oRes->IsOK() ){ $this->SetError("SQL error [".$oRes->GetError()."] SQL: [$sSQL]"); return null; }
// --- Add the Properties to the Class --- //
// Temp array to store matched id properties //
$aoMatchedIdProps = Array();
// For each row (which represent columns in the table)
while( $a = $oRes->FetchRow(MYSQL_ASSOC) ){
$oColObject = $this->CreateColumnTypeObject( $a['Type'], $a['Null']=='YES', $a['Default'] );
if( null === $oColObject ){
$this->SetError("Table column [$sTable.".$a['Field']."]: ".$this->GetError()." in ".__METHOD__." @ ".__LINE__);
$oClass = null; break;
}
$oProp = $oClass->AddProperty($a['Field'], $oColObject );
$oProp->SetNull($a['Null']=='YES');
// ID property
if( 'PRI' == $a['Key'] ){
// Check whether the old Class has the same ID Property
if( !$oClassOld->HasIdProperty($oProp->GetName()) ){
$this->SetError("Table column [$sTable.".$a['Field']."]: Extended Class [$sClassNameOld] doesn't have the ID column [".$oProp->GetName()."] in ".__METHOD__." @ ".__LINE__);
$oClass = null; break;
}
$oClass->AddIdProperty($oProp); // To se tam dostane z CreateClassByTable()
// Add this old Class' Property to the list of matched ID Properties
$oOldClass_IdProp = $oClassOld->GetProperty($oProp->GetName());
$aoMatchedIdProps[] = $oOldClass_IdProp;
}
$oProp->SetUnique( 'PRI' == $a['Key'] || 'UNI' == $a['Key'] );
}
$oRes->FreeResult();
// Check whether all ID Properties of old Class were matched
foreach( $oClassOld->GetIdProperties() as $oOldClass_IdProp){
if( !in_array($oOldClass_IdProp, $aoMatchedIdProps) ){
$this->SetError("Extended Class [$sClassNameOld] doesn't have the ID column [".$oOldClass_IdProp->GetName()."] in ".__METHOD__." @ ".__LINE__);
$oClass = null; break;
}
}
if($oClass) $this->AddClassIntoDictionary($oClass);
return $oClass;
}// cDwObjectPersistence::ExtendClassByTable()
/**<**********************************************************************************>
* Returns cDwOpColumnType object according to the definition in $sTypeString. *
**************************************************************************************/
function CreateColumnTypeObject($sTypeString, $bNull, $sDefault){
$oRet = null;
//$sTypeName = substr( $sTypeString, 0, strpos($sTypeString, '(') );
//if( !ereg( '(.*)(\\((.*)\\))?(.*)?', $sTypeString, $asParts ) ) return $oRet;
//$asParts = array_map('strtoupper', array_map('trim', $asParts) );
//echo "<pre>\$asParts: ".AdjustedPrintR($asParts)."</pre>";///
// list($sTypeName, $sData, $sUnsigned) = $asParts;
$sTypeName = strtoupper(trim(strtok($sTypeString, '(') ));
$sData = (trim(strtok(')') ));
$sUnsigned = strtoupper(trim(strtok('') ));
//echo "<pre>$sTypeName, $sData, $sUnsigned</pre>";///
$sClassName = 'cDwOpColumnType_';
/*switch($sTypeName){
case 'VARCHAR':
case '': $sClassName = '_'.$sTypeName; break;
}/**/
$saImplementedColumnTypes = DWOP_IMPLEMENTED_COLUMN_TYPES;
$asImplementedTypes = array_map('trim', explode(',', $saImplementedColumnTypes));
if( !in_array( $sTypeName, $asImplementedTypes) ){ $this->SetError("Column type [$sTypeName] not implemented."); return null; }
$sClassName .= $sTypeName;
if( $sUnsigned == 'UNSIGNED' )
$sClassName .= '_UNSIGNED';
if(!class_exists($sClassName)){ $this->SetError("Undefined column class [$sClassName]."); return null; }
switch($sTypeName){
case 'ENUM': case 'SET':
$oRet = new $sClassName($sData); break;
case 'CHAR': case 'VARCHAR':
$oRet = new $sClassName((int)$sData); break;
default:
$oRet = new $sClassName(); break;
}
if( $oRet ){
$oRet->SetDefault($sDefault);
$oRet->SetNull($bNull);
}
return $oRet;
}// cDwObjectPersistence::CreateColumnTypeObject()
/**<***********************************************************************>
* Sets M : N relation between two classes using third class as a glue. *
***************************************************************************/
function SetMnRelation($oClass1, $oClassGlue, $oClass2){
$bSucc = false;
do{
// Convert class names to Class objects and check the existence of the class.
if( !($oClass1 = $this->ConvertAndCheckClass($oClass1)) ){ $this->SetError("!oClass1 in ".__METHOD__." @ ".__LINE__); break; }
if( !($oClass2 = $this->ConvertAndCheckClass($oClass2)) ){ $this->SetError("!oClass2 in ".__METHOD__." @ ".__LINE__); break; }
if( !($oClassGlue = $this->ConvertAndCheckClass($oClassGlue)) ){ $this->SetError("!oClassGlue in ".__METHOD__." @ ".__LINE__); break; }
// Check all classes whether suitable (PRIMARY KEYs etc.)
if( !$oClass1->IsSuitableForMnRelationSide() ){ $this->SetError("Class ".$oClass1->GetName()." not suitable for M:N side in ".__METHOD__." @ ".__LINE__); break; }
if( !$oClass2->IsSuitableForMnRelationSide() ){ $this->SetError("Class ".$oClass2->GetName()." not suitable for M:N side in ".__METHOD__." @ ".__LINE__); break; }
if( !$oClassGlue->IsSuitableForMnRelationGlue() ){ $this->SetError("Class ".$oClassGlue->GetName()." not suitable for M:N glue in ".__METHOD__." @ ".__LINE__); break; }
// Check whether the types are the same
$oIdProp1 = $oClass1->GetIdProperty();
$oIdProp2 = $oClass1->GetIdProperty();
$aoIdProps = $oClassGlue->GetIdProperties();
if( $oIdProp1->GetColType()->GetType() != $aoIdProps[0]->GetColType()->GetType() ){
$this->SetError('Property types mismatch: "'.$oIdProp1->GetName().'" and "'.$aoIdProps[0]->GetName().' in '.__METHOD__.' @ '.__LINE__); break; }
if( $oIdProp2->GetColType()->GetType() != $aoIdProps[1]->GetColType()->GetType() ){
$this->SetError('Property types mismatch: "'.$oIdProp2->GetName().'" and "'.$aoIdProps[1]->GetName().' in '.__METHOD__.' @ '.__LINE__); break; }
//$oIdProp1->CompareTo($aoIdProps[0]); // TODO
$b = $oClassGlue->SetMnRelationGlue($oClass1, $oClass2, $aoIdProps[0], $aoIdProps[1]);
if( !$b ){ $this->SetError("!\$oClassGlue->SetMnRelationGlue @ ".__LINE__); break; }
$bSucc = true;
}while(false);
return $bSucc;
}
/**<*********************************************************************************************>
* *
@param $oObject1 is an object of which related objects of $oClass2 should be returned.
@param $oClass2 - can be:
(object) - the Class will be found by it's class name.
(cDwOpClass) Class object - that's what we need
(string) class name - the Class will be found in the dictionary.
*************************************************************************************************/
function LoadObjectsByMnRelation($oObject, $oClassGlue, $oClass2, $xId=null){
$bSucc = false;
do{
// Convert class names to Class objects and check the existence of the class.
if( !($oClass1 = $this->ConvertAndCheckClass($oObject)) ){ $this->SetError("!oClass1 @ ".__LINE__); break; }
if( !($oClass2 = $this->ConvertAndCheckClass($oClass2)) ){ $this->SetError("!oClass2 @ ".__LINE__); break; }
if( !($oClassGlue = $this->ConvertAndCheckClass($oClassGlue)) ){ $this->SetError("!oClassGlue @ ".__LINE__); break; }
if( !$oClassGlue->IsMnRelationGlue() ){ $this->SetError($oClassGlue->GetName()." is not a M : N relation glue in ".__METHOD__." @ ".__LINE__); break; }
// Table names
$sTable1 = $oClass1->GetTable();
$sTable2 = $oClass2->GetTable();
$sTableGlue = $oClassGlue->GetTable();
// Column names
$oClass1IdProp = $oClass1->GetIdProperty();
$sIdCol1 = $oClass1IdProp->GetColName();
$sIdCol2 = $oClass2->GetIdProperty()->GetColName();
$sGluePropFrom = $oClassGlue->oMnRelationProp1->GetColName();
$sGluePropTo = $oClassGlue->oMnRelationProp2->GetColName();
if( is_object($oObject) )
$xId = $oClass1IdProp->FormatForSql( $oObject->GetId() );
//if( !$xId ){ $this->SetError("Bad ID [$xId] in ".__METHOD__." @ ".__LINE__); break; }
// Create SQL
$sSQL = "
-- Vypise reklamy a k nim kanaly, ktere jsou s reklamou spojeny.
SELECT table_to.*
FROM $sTable1 AS table_from
INNER JOIN $sTableGlue AS glue ON table_from.$sIdCol1 = glue.$sGluePropFrom
LEFT JOIN $sTable2 AS table_to ON glue.$sGluePropTo = table_to.$sIdCol2
WHERE table_from.$sIdCol1 = $xId
;";
$aoObjects = $this->LoadObjectsBySql($oClass2, $sSQL);
$bSucc = true;
}while(false);
return $aoObjects;
}
}// cDwObjectPersistence
/**<***********************************************************************>
* cDwOpClass *
***************************************************************************/
class cDwOpClass {
var $sName;
function GetName() { return $this->sName; }
function SetName($sName){ $this->sName = $sName; }
var $sTable;
function GetTable() { return $this->sTable; }
function SetTable($sTable){ $this->sTable = $sTable; }
var $oParentClass = null;
function GetParentClass() { return $this->oParentClass; }
function _SetParentClass($oParentClass){ $this->oParentClass = $oParentClass; }
// -- Constructor -- //
function cDwOpClass( $sName, $sTable ){ $this->sName = $sName; $this->SetTable($sTable); }
// Properties //
var $aoProperties;
/** @returns cDwOpProperty[] array of this class' properties. */
function GetProperties() { return $this->aoProperties; }
/** @returns cDwOpProperty this class' property of given name or NULL if the class does not have such. */
function GetProperty($sColName){
if( isset($this->aoProperties[$sColName]) )
$oRet = $this->aoProperties[$sColName];
else $oRet = null;
return $oRet;
}
function AddPropertyObject($oProperty){ return $this->aoProperties[$oProperty->GetColName()] = $oProperty; }
function AddProperty($sColName, $oColType){
$oProp = new cDwOpProperty($sColName, $oColType);
$this->aoProperties[$sColName] = $oProp;
return $oProp;
}
function RemProperty($sColName){
if( !isset($this->aoProperties[$sColName]) ) return false;
unset($this->aoProperties[$sColName]);
return true;
}
function GetNonKeyProperties(){
$aoProps = Array();
foreach( $this->aoProperties as $oProp ){
//if( $oProp->IsKeyProp() ) continue;
$aoProps[] = $oProp;
}
return $aoProps;
}
// --- M : N relation stuff --- //
// -- Is this class M : N relation "glue"? -- //
var $bMnRelationGlue = false;
function IsMnRelationGlue() { return $this->bMnRelationGlue; }
function UnsetMnRelationGlue(){ $this->bMnRelationGlue = false; }
var $oMnRelationClass1 = null;
var $oMnRelationClass2 = null;
function GetMnRelationClass1() { return $this->oMnRelationClass1; }
function GetMnRelationClass2() { return $this->oMnRelationClass2; }
function GetMnRelationOtherClass($oClass){
if( $oClass === $this->oMnRelationClass1 ) return $this->oMnRelationClass2;
if( $oClass === $this->oMnRelationClass2 ) return $this->oMnRelationClass1;
return null;
}
var $oMnRelationProp1 = null;
var $oMnRelationProp2 = null;
function GetMnRelationProp1() { return $this->oMnRelationProp1; }
function GetMnRelationProp2() { return $this->oMnRelationProp2; }
function GetMnRelationOtherProp($oProp){
if( $oProp === $this->oMnRelationProp1 ) return $this->oMnRelationProp2;
if( $oProp === $this->oMnRelationProp2 ) return $this->oMnRelationProp1;
return null;
}
function GetMnRelationPropForClass($oClass){
//App::Log($oClass->GetName()." ==? ".$this->oMnRelationClass1->GetName());///
//App::Log($oClass->GetName()." ==? ".$this->oMnRelationClass2->GetName());///
//if( $oClass === $this->oMnRelationClass1 ) return $this->oMnRelationProp1;
//if( $oClass === $this->oMnRelationClass2 ) return $this->oMnRelationProp2;
$asParents = class_parents($oClass->GetName());
array_unshift($asParents, $oClass->GetName());
//App::Log(implode(',',$asParents)." <==? ".$this->oMnRelationClass1->GetName());///
//App::Log(implode(',',$asParents)." <==? ".$this->oMnRelationClass2->GetName());///
if( in_array($this->oMnRelationClass1->GetName(), $asParents)){ return $this->oMnRelationProp1; }
if( in_array($this->oMnRelationClass2->GetName(), $asParents)){ return $this->oMnRelationProp2; }
return null;
}
function IsSuitableForMnRelationGlue(){ return Count($this->aoIdProperties) == 2; }
function IsSuitableForMnRelationSide(){ return Count($this->aoIdProperties) == 1; }
function SetMnRelationGlue($oClass1, $oClass2, $oProp1, $oProp2){
$this->bMnRelationGlue = false;
do{
// Check everything and return false on failure.
if( !$this->IsSuitableForMnRelationGlue() ) return false;
if( !$oClass1 || !($oClass1 instanceof cDwOpClass) ) return false;
if( !$oClass2 || !($oClass2 instanceof cDwOpClass) ) return false;
if( 1 != $oClass1->GetIdPropertiesCount() ) return false;
if( 1 != $oClass2->GetIdPropertiesCount() ) return false;
if( is_string($oProp1) ) $oProp1 = $this->GetProperty($oProp1);
if( is_string($oProp2) ) $oProp2 = $this->GetProperty($oProp2);
if( null == $oProp1 || !($oProp1 instanceof cDwOpProperty) ) return false;
if( null == $oProp2 || !($oProp2 instanceof cDwOpProperty) ) return false;
// Seems to be ok, set the relation for this Class... (we have to set the sides, too)
$this->oMnRelationClass1 = $oClass1;
$this->oMnRelationClass2 = $oClass2;
$this->oMnRelationProp1 = $oProp1;
$this->oMnRelationProp2 = $oProp2;
$this->bMnRelationGlue = true;
}while(false);
return $this->bMnRelationGlue;
}
// --- ID properties --- //
// ID property //
//var $oIdProperty;
function GetIdProperty() { reset($this->aoIdProperties); return current($this->aoIdProperties); }
function SetIdProperty($oIdProperty){
if(!$oIdProperty){ $this->aoIdProperties = Array(); return; }
$this->aoIdProperties = Array( $oIdProperty );
$oIdProperty->SetPrimaryKeyPart(true);
}
var $aoIdProperties = Array();
function GetIdProperties() { return $this->aoIdProperties; }
function GetIdPropertiesCount() { return Count($this->aoIdProperties); }
/**<**********************************************************************************>
* @returns whether Class has given ID property or ID property of given name *
**************************************************************************************/
function HasIdProperty($xProp){
if( is_string($xProp) ) $xProp = $this->GetProperty($xProp);
if( !$xProp ) return false;
if( in_array($xProp, $this->aoIdProperties) ) return true;
return false;
}
function AddIdProperty($oProperty){ array_push($this->aoIdProperties, $oProperty); $oProperty->SetPrimaryKeyPart(true); }
/** @returns string Coma separated list of ID (PRIMARY KEY) values of the given object. */
function GetIdPropertiesSql($oObject, $sGlue=', '){
$asPropSqls = Array();
foreach( $this->GetIdProperties() as $oProp ){
$asPropSqls[] = $oProp->GetColName() . " = " . $oProp->FormatForSql( $oObject->GetProperty($oProp->GetName()) );
}
$saPropSqls = implode($sGlue, $asPropSqls);
//if( '' != $saPropSqls ) $saPropSqls = " WHERE $saPropSqls "; // We don't want this for ID - can be "ON ...", e.g.
return $saPropSqls;
}
/** @returns string Formatted list of ID (PRIMARY KEY) values of the given object. */
function GetObjectMultiIdString($oObject, $iMode=DWOP_VALUE_DUMP_MODE__SQL){
switch($iMode){
default: trigger_error("Bad param 2 - must be one of DWOP_VALUE_DUMP_MODE__* constants"); return null; break;
case DWOP_VALUE_DUMP_MODE__SQL: $sGlue=', '; $sEq=' = '; $fFunc='sql'; break;
case DWOP_VALUE_DUMP_MODE__SQL_SHORT: $sGlue=','; $sEq='='; $fFunc='sql'; break;
case DWOP_VALUE_DUMP_MODE__SQL_VALUES: $sGlue=','; $sEq=''; $fFunc='sql'; break;
case DWOP_VALUE_DUMP_MODE__ESCAPED_VALUES: $sGlue='\''; $sEq=''; $fFunc='addslashes'; break; // Shortest unique
case DWOP_VALUE_DUMP_MODE__COMA: $sGlue=', '; $sEq=''; $fFunc=''; break;
}
$asPropSqls = Array();
foreach( $this->GetIdProperties() as $oProp ){
$s = '';
if($sEq) $s .= $oProp->GetColName() . $sEq; // <col name> =
$xVal = $oObject->GetProperty($oProp->GetName());
if(!$fFunc) ;
elseif( 'sql' == $fFunc ) $xVal = $oProp->FormatForSql( $xVal );
else/*if( function_exists($fFunc) ) */$xVal = $fFunc($xVal);
//else ;
$s .= $xVal;
$asPropSqls[] = $s;
}
$saPropSqls = implode($sGlue, $asPropSqls);
//if( '' != $saPropSqls ) $saPropSqls = " WHERE $saPropSqls "; // We don't want this for ID - can be "ON ...", e.g.
return $saPropSqls;
}
/** Sets ID properties.
@param $xProperties can be:
- a Property name
- coma separated list of Property names
- array of Property objects
*/
function SetIdProperties($xProperties){
// If $xProperties param is string, convert to an array
if( is_string($xProperties) )
$xProperties = array_map('trim', explode(',', $xProperties));
// Now the $xProperties must be an array.
if( !is_array($xProperties) ){
$this->aoIdProperties = Array();
return false;
}
// Go through all properties in the array and transform them to cDwOpIdingInfo objects.
$aoIdProperties = Array();
foreach( $xProperties as $xProperty ){
$bDesc = false;
// If the array item is a string, convert to a property object.
if( is_string($xProperty) )
$xProperty = $this->GetProperty($xProperty);
// If the $xProperty is not a cDwOpProperty object, move on.
if( null === $xProperty || !($xProperty instanceof cDwOpProperty) )
continue;
$xProperty->SetPrimaryKeyPart(true);
$aoIdProperties[] = $xProperty;
}
$this->aoIdProperties = $aoIdProperties;
//echo "<pre>".AdjustedPrintR($aoOrderProperties)."</pre>";///
}// SetIdProperties($xProperties)
// --- Order properties --- //
var $aoOrderProperties = Array();
function GetOrderProperties() { return $this->aoOrderProperties; }
/** @returns string Coma separated list of Order Properties (column names). */
function GetOrderPropertiesSql(){
$asPropSqls = Array();
foreach( $this->aoOrderProperties as $oOrderingInfo ){
$asPropSqls[] = $oOrderingInfo->oProperty->GetColName() . ($oOrderingInfo->bDesc ? ' DESC' : ' ASC');
}
$saPropSqls = implode(', ', $asPropSqls);
if( '' != $saPropSqls ) $saPropSqls = " ORDER BY $saPropSqls ";
return $saPropSqls;
}
/**<*************************************************************************>
* Sets the ordering information for this class. Previous info is replaced. *
@param $xProperties can be a coma separated list of Property names,
an array of Property names, or
an array of Property objects.
*****************************************************************************/
function SetOrderProperties($xProperties){
// If $xProperties param is string, convert to an array
if( is_string($xProperties) )
$xProperties = array_map('trim', explode(',', $xProperties));
// Now the $xProperties must be an array.
if( !is_array($xProperties) )
return false;
// Go through all properties in the array and transform them to cDwOpOrderingInfo objects.
$aoOrderProperties = Array();
foreach( $xProperties as $xProperty ){
$bDesc = false;
// If the array item is a string, convert to a property object.
if( is_string($xProperty) ){
if( '' == $xProperty ) continue;
if( $xProperty[0] == '+' || $xProperty[0] == '-' ){
$bDesc = ( $xProperty[0] == '-' );
$xProperty = substr($xProperty, 1);
}
$xProperty = $this->GetProperty($xProperty);
}
// Instance of cDwOpProperty - convert to cDwOpOrderingInfo
if( $xProperty instanceof cDwOpProperty ){
$xProperty = new cDwOpOrderingInfo($xProperty, $bDesc);
}
// If the $xProperty is not a cDwOpProperty object, move on.
if( null === $xProperty || !($xProperty instanceof cDwOpOrderingInfo) )
continue;
$aoOrderProperties[] = $xProperty;
}
$this->aoOrderProperties = $aoOrderProperties;
//echo "<pre>".AdjustedPrintR($aoOrderProperties)."</pre>";///
}// SetOrderProperties($xProperties)
}// class cDwOpClass
/**<***********************************************************************>
* Holds information about ordering property - for cDwOpClass. *
***************************************************************************/
class cDwOpOrderingInfo {
var $oProperty = null;
var $bDesc = false;
function cDwOpOrderingInfo($oProperty, $bDesc=false){
$this->oProperty = $oProperty;
$this->bDesc = $bDesc;
}
}
/**<***********************************************************************>
* cDwOpProperty *
***************************************************************************/
class cDwOpProperty {
/** Name - currently we use the same as a Property name and database column name. */
//var $sName = null;
function GetName() { return $this->sColName; }
function SetName($sColName){ $this->sColName = $sColName; }
/** Column name - currently used also as the name of the property */
var $sColName = null;
function GetColName() { return $this->sColName; }
function SetColName($sColName){ $this->sColName = $sColName; }
/** Column type - an object derived from cDwOpColumnType class. */
var $oColType = null;
/** @returns cDwOpColumnType column type representing this property. */
function GetColType() { return $this->oColType; }
function SetColType($oColType){ $this->oColType = $oColType; }
/** Whether the property is a part of a PRIMARY KEY for this Class. */
var $bPrimaryKeyPart = false;
function IsPrimaryKeyPart() { return $this->bPrimaryKeyPart; }
function SetPrimaryKeyPart($bPrimaryKeyPart){ $this->bPrimaryKeyPart = $bPrimaryKeyPart; }
/** Whether the property is a FOREIGN KEY. */
var $bForeignKey = false;
function IsForeignKey() { return $this->bForeignKey; }
function SetForeignKey($bForeignKey){ $this->bForeignKey = $bForeignKey; }
/** Whether the property is unique across all objects of this Class. */
var $bUnique = false;
function IsUnique() { return $this->bUnique; }
function SetUnique($bUnique){ $this->bUnique = $bUnique; }
/** Whether this property can be NULL. */
var $bCanBeNull = false;
function IsNull() { return $this->bCanBeNull; }
function SetNull($bCanBeNull){ $this->bCanBeNull = $bCanBeNull; }
function IsKey(){
return $this->IsPrimaryKeyPart() || $this->IsForeignKey() || $this->IsUnique();
}
// -- Constructor -- //
function cDwOpProperty($sColName, $oColType, $bUnique=false){
$this->SetColName($sColName);
$this->SetColType($oColType);
$this->SetUnique($bUnique);
}
/** @returns SQL literal representing a value $xVal if it was held by this property. */
function FormatForSql($xVal){
if( null === $xVal && $this->GetColType()->IsNull() )
return 'NULL';
//echo "\n".CallInfo()."; Val: ".$xVal." ColType:".$this->GetColType()->GetName();///
return $this->GetColType()->FormatForSql($xVal);
}
}// class cDwOpProperty
/**<***********************************************************************>
* cDwOpColumnType *
***************************************************************************/
abstract class cDwOpColumnType {
var $sName;
function GetName() { return $this->sName; }
function SetName($sName){ $this->sName = $sName; }
var $iType;
/** @returns one of type constants: DWOP_TYPE_STR,DWOP_TYPE_NUM,DWOP_TYPE_BOOL,DWOP_TYPE_ENUM,DWOP_TYPE_SET, DWOP_TYPE_REAL */
function GetType() { return $this->iType; }
/** @param iType one of type constants: DWOP_TYPE_STR,DWOP_TYPE_NUM,DWOP_TYPE_BOOL,DWOP_TYPE_ENUM,DWOP_TYPE_SET, DWOP_TYPE_REAL */
function SetType($iType){
if(!in_array($iType, Array(DWOP_TYPE_STR,DWOP_TYPE_NUM,DWOP_TYPE_BOOL,DWOP_TYPE_ENUM,DWOP_TYPE_SET, DWOP_TYPE_REAL))){
user_error("cDwOpColumnType::SetType(): Param \$iType must be some of DWOP_TYPE_* constants.");
}
$this->iType = $iType;
}
// Can be NULL?
var $bCanBeNull = true;
function IsNull() { return $this->bCanBeNull; }
function SetNull($bCanBeNull){ $this->bCanBeNull = $bCanBeNull; }
// Default value
var $xDefault;
function GetDefault() { return $this->xDefault; }
function SetDefault($xDefault){
$bRet = true;
if( (null === $xDefault && !$this->IsNull() ) // Default value being set is NULL and must not be null
|| ( !$this->CheckValue($xDefault) ) // or the default value is not allowed for this type,
){
$xDefault = $this->GetDefaultDefault(); // then set the default to the default default,
$bRet = false; // and indicate failure by returning false.
}
$this->xDefault = $xDefault;
return $bRet;
}
//function GetDefaultDefault(){ user_error(__METHOD__.' must be overriden.'); return null; }
function GetDefaultDefault(){
switch( $this->GetType() ){
case DWOP_TYPE_STR: return ''; break;
case DWOP_TYPE_NUM: return 0; break;
case DWOP_TYPE_BOOL: return false; break;
case DWOP_TYPE_ENUM: return ''; break;
case DWOP_TYPE_SET: return ''; break;
case DWOP_TYPE_REAL: return 0.0; break;
}
}
// Aditional data - possible values for ENUM and SET, etc
//var $aData;
/**<***********************************************************************>
* Constructor *
***************************************************************************/
function cDwOpColumnType($iFlags=0, $xDefault=null){
// Flags
if( $iFlags & DWOP_NOT_NULL )
$this->SetNull(false);
//if( $iFlags & DWOP_BINARY )
// $this->SetBinary(true);
// Default value
$this->SetDefault( $xDefault );
}// cDwOpColumnType::cDwOpColumnType()
// Useless
/*function cDwOpColumnType($sName, $iType, $aData){
$this->SetName($sName);
$this->SetType($iType);
$this->aData = $aData;
}// cDwOpColumnType::cDwOpColumnType()
/**/
/**<***********************************************************************>
* @returns the value in $xVal in the format suitable for SQL. *
***************************************************************************/
function FormatForSql($xVal){
//App::Log( CallInfo()." \$xVal: (".gettype($xVal).") $xVal" );
$sRet = null;
if( null === $xVal ){
if( $this->IsNull() )
$sRet = 'NULL';
else
$sRet = 'nULl';
}
else switch($this->GetType()){
case DWOP_TYPE_STR: $sRet = asq((string)$xVal); break;
case DWOP_TYPE_NUM: $sRet = (double)$xVal; /*echo "<br>XXX".CallInfo(-2)."<br>".CallInfo(-3);*/ break;
case DWOP_TYPE_BOOL: $sRet = (integer)(boolean)$xRet; break;
case DWOP_TYPE_ENUM: $sRet = asq((string)$xVal); break;
case DWOP_TYPE_SET: $sRet = asq((string)$xVal); break;
case DWOP_TYPE_REAL: $sRet = (double)$xVal; break;
//case DWOP_TYPE_: $sRet = ; break;
default: trigger_error('Unknown value type! in '.__METHOD__.' @ '.__LINE__); $sRet = asq((string)$xVal); break;
}
//App::Log( CallInfo()." \$sRet: $sRet" );
return $sRet;
}
function ConvertFromResult($xVal){ return $xVal; }
/**<***********************************************************************>
* Check whether the variable can fit in the column. *
***************************************************************************/
function CheckValue($xVal /*, $oProperty*/){
if( null === $xVal && !$this->IsNull() )
return false;
$bFits = true;
switch($this->GetType()){
case DWOP_TYPE_STR: $bFits = is_string($xVal) || is_numeric($xVal); break;
case DWOP_TYPE_NUM: $bFits = is_bool($xVal) || is_int($xVal); break;
case DWOP_TYPE_BOOL: $bFits = is_bool($xRet) || is_int($xVal); break;
//case DWOP_TYPE_ENUM: $bFits = is_string($xVal) /*&& in_array($xVal, $this->asMembers)/**/; break;
case DWOP_TYPE_SET:
$asMembers = array_map('trim', explode(',', $xVal));
foreach( $asMembers as $sMember ){
if( !in_array($xVal, $this->aData) ){ $bFits = false; break; }
}
break;
}
return $bFits;
}
}// class cDwOpColumnType
/**<***********************************************************************>
* cDwOpColumnTypesRepository *
Skladiste casto pouzivanych typu sloupcu.
Nema cenu sem davat stringy - lisi se delkou.
Mozna je to uplne zbytecna trida...
***************************************************************************/
/*class cDwOpColumnTypesRepository {
var $aoColumnTypes;
function AddColumnType($sKey, &$oType){ $this->aoColumnTypes[$sKey] =& $oType; }
function cDwOpColumnTypesRepository(){
$this->aoColumnTypes = Array();
$oType =& new cDwOpColumnType_INT();
$this->AddColumnType('INT', $oType);
$oType =& new cDwOpColumnType_INT_UNSIGNED();
$this->AddColumnType('INT UNSIGNED', $oType);
$oType =& new cDwOpColumnType_SMALLINT();
$this->AddColumnType('SMALLINT', $oType);
$oType =& new cDwOpColumnType_SMALLINT_UNSIGNED();
$this->AddColumnType('SMALLINT UNSIGNED', $oType);
}// cDwOpColumnTypesRepository()
function &GetColumnType($sName){
return isset( $this->aoColumnTypes[$sName] ) ? $this->aoColumnTypes[$sName] : null;
}
}// class cDwOpColumnTypesRepository
/**/
/** ************************************************************************
* Simple class that holds item's ID and a hashmap of parameters. *
***************************************************************************/
abstract class DwFwIdAndProperties {
function DwFwIdAndProperties($iId=null){
$this->SetId($iId);
}
var $sId;
function GetId() { return $this->sId; }
function SetId($sId){ $this->sId = $sId; }
var $asParams = Array();
function SetProperty($sName, $sValue){ $this->asParams[(string)$sName] = $sValue; }
function GetProperty($sName){ return isset($this->asParams[(string)$sName]) ? $this->asParams[(string)$sName] : null; }
//function HasProperty($sName){ return isset($this->asParams[(string)$sName]); }
function HasProperty($sName){ return array_key_exists((string)$sName, $this->asParams); }
function IsPropertySet($sName){ return $this->HasProperty($sName); }
function GetProperties(){ return $this->asParams; }
function SetProperties($asParams, $bOverwrite=true){
foreach( $asParams as $sName => $sValue ){
if($bOverwrite || !isset($this->asParams[(string)$sName]))
$this->asParams[(string)$sName] = $sValue;
}
}
function DwFwIdAndParams($sId=null){ $this->sId = $sId; }
}// class DwFwIdAndParams
/** ************************************************************************
* Simple class that holds item's ID and a hashmap of parameters. *
***************************************************************************/
abstract class DwFwIdAndProperties {
function DwFwIdAndProperties($iId=null){
$this->SetId($iId);
}
var $sId;
function GetId() { return $this->sId; }
function SetId($sId){ $this->sId = $sId; }
var $asParams = Array();
function SetProperty($sName, $sValue){ $this->asParams[(string)$sName] = $sValue; }
function GetProperty($sName){ return isset($this->asParams[(string)$sName]) ? $this->asParams[(string)$sName] : null; }
//function HasProperty($sName){ return isset($this->asParams[(string)$sName]); }
function HasProperty($sName){ return array_key_exists((string)$sName, $this->asParams); }
function IsPropertySet($sName){ return $this->HasProperty($sName); }
function GetProperties(){ return $this->asParams; }
function SetProperties($asParams, $bOverwrite=true){
foreach( $asParams as $sName => $sValue ){
if($bOverwrite || !isset($this->asParams[(string)$sName]))
$this->asParams[(string)$sName] = $sValue;
}
}
function DwFwIdAndParams($sId=null){ $this->sId = $sId; }
}// class DwFwIdAndParams
/***************************************************************************
* User *
***************************************************************************/
class cObjectPersistenceTestClass_User extends DwFwIdAndProperties {
function GetProperty($sName) {
if( 'id' == $sName ) return $this->GetId();
else return parent::GetProperty($sName);
}
function SetProperty($sName, $sValue){
if( 'id' == $sName ) return $this->SetId($sValue);
else return parent::SetProperty($sName, $sValue);
}
}// class cObjectPersistenceTestClass_User
/***************************************************************************
* Door *
***************************************************************************/
class cObjectPersistence_TestClass_Door extends DwFwIdAndProperties {
function GetProperty($sName) {
if( 'id' == $sName ) return $this->GetId();
else return parent::GetProperty($sName);
}
function SetProperty($sName, $sValue){
if( 'id' == $sName ) return $this->SetId($sValue);
else return parent::SetProperty($sName, $sValue);
}
}// class cObjectPersistenceTestClass_User
/***************************************************************************
* Key *
***************************************************************************/
class cObjectPersistence_TestClass_Key extends DwFwIdAndProperties {
function GetProperty($sName) {
if( 'id' == $sName ) return $this->GetId();
else return parent::GetProperty($sName);
}
function SetProperty($sName, $sValue){
if( 'id' == $sName ) return $this->SetId($sValue);
else return parent::SetProperty($sName, $sValue);
}
}// class cObjectPersistenceTestClass_User
// Create DB object
$oDB = new cDBAccess_MySQL('localhost:3350', 'test', 'test', 'test', 'cp1250');
$oDB->SetSelectMode(CDBA_SELECT_RETURNS_CRESULT_ON_ERROR);
echo "Connect: ".///
$oDB->Connect();
echo "<br/>\n";///
//$xVal = $oDB->SelectCell("SELECT NULL"); // Test what NULL looks like in PHP
//echo "\n".gettype($xVal)." ".ord($xVal); die();
// Create Object Persistence object
$oOP = new cDwObjectPersistence_DB($oDB);
//$oColTypes =& new cDwOpColumnTypesRepository();
CREATE TABLE `ap_users` (
`id` int(10) unsigned NOT NULL auto_increment,
`user` varchar(255) NOT NULL,
`pass` varchar(40) default NULL,
`fname` varchar(255) NOT NULL,
`lname` varchar(255) NOT NULL,
`addr` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`state` enum('good', 'bad') NOT NULL DEFAULT 'good',
`psc` varchar(255) NOT NULL,
`ctry` tinyint(3) unsigned NOT NULL,
`ppal` varchar(255) default NULL
);
INSERT INTO ap_users (id, user) VALUES
(10001, 'Ondra')
, (10002, 'Zdenek')
, (10003, 'Martin')
, (10004, 'Zuzka')
, (10005, 'David')
, (10006, 'Satan')
;
CREATE TABLE ap_doors (
id INT UNSIGNED NOT NULL auto_increment PRIMARY KEY,
txt VARCHAR(15)
);
INSERT INTO ap_doors VALUES (330, 'Nebe'), (118, 'Bazina'), (116, 'Peklo'), (110, 'Curaprox'), (222, 'Neznamo');
CREATE TABLE ap_keys (
id_user INT UNSIGNED NOT NULL,
id_door INT UNSIGNED NOT NULL,
PRIMARY KEY pk( id_user, id_door )
);
INSERT INTO ap_keys VALUES
(10001, 330), (10001, 118), (10001, 110), -- Ondra
(10002, 118), (10002, 116), -- Zdenek
(10003, 118), (10003, 330), (10003, 116), -- Martin
(10004, 110), (10004, 330), -- Zuzka
(10006, 116), (10006, 118); -- Satan
$oClass = new cDwOpClass('cObjectPersistenceTestClass_User', 'ap_users');
//$oProp = $oClass->AddProperty('id', $oColTypes->GetColumnType('INT UNSIGNED'));
$oProp = $oClass->AddProperty('id', new cDwOpColumnType_INT_UNSIGNED() );
$oClass->SetIdProperty($oProp);
$oProp = $oClass->AddProperty('user', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('pass', new cDwOpColumnType_VARCHAR(40, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('fname', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('lname', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('addr', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('city', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('state', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('psc', new cDwOpColumnType_VARCHAR(255, DWOP_NOT_NULL) );
$oProp = $oClass->AddProperty('ctry', new cDwOpColumnType_TINYINT_UNSIGNED() );
$oProp = $oClass->AddProperty('ppal', new cDwOpColumnType_VARCHAR(255) );
$oClass->SetOrderProperties('lname, +fname, -id');
$oOP->AddClassIntoDictionary($oClass);
/*/
$oClass = $oOP->CreateClassByTable('cObjectPersistenceTestClass_User', 'ap_users');
$oClass->SetOrderProperties('lname, +fname, -id');
//file_put_contents('x1.txt', AdjustedPrintR($oClass));///
//echo "<pre>\$oClass: ".AdjustedPrintR($oClass)."</pre>";///
srand(time());
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load by ID
echo "<h3>Load by ID</h3>";
$iID = 1;
echo "<pre>\$oObject = \$oOP->LoadObjectById(".$oClass->GetName().", $iID);</pre>";
$oUser = $oOP->LoadObjectById($oClass, $iID);
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load by ID, using class name string
echo "<h3>Load by ID, using class name string</h3>";
$iID = 1;
echo "<pre>\$oObject =& \$oOP->LoadObjectById('".$oClass->GetName()."', $iID);</pre>";
$oUser =& $oOP->LoadObjectById($oClass->GetName(), $iID);
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load by value
echo "<h3>Load by value</h3>";
$xVal = 'as';
echo "<pre>\$aoUsers = \$oOP->LoadObjectsByValue(".$oClass->GetName().", 'user', $xVal);</pre>";
$aoUsers = $oOP->LoadObjectsByValue($oClass, 'user', $xVal);
echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Save
echo "<h3>Save</h3>";
$oUser = new cObjectPersistenceTestClass_User();
$oUser->SetId(1);
$oUser->SetProperty('user', 'as'.rand());
$oUser->SetProperty('pass', 'as');
$oUser->SetProperty('fname', 'Astar');
$oUser->SetProperty('lname', 'Seran');
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<pre>\$oOP->SaveObject(\$oUser);</pre>";
$bSucc = $oOP->SaveObject($oUser);
echo "<div>".($bSucc ? 'saved' : 'error')."</div>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Create
echo "<h3>Create</h3>";
$oUser = new cObjectPersistenceTestClass_User();
$oUser->SetId(null);
$oUser->SetProperty('user', 'as'.rand());
$oUser->SetProperty('pass', 'as');
$oUser->SetProperty('fname', 'Astar');
$oUser->SetProperty('lname', 'Seran');
echo "<pre>oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<pre>\$oOP->SaveObject(\$oUser);</pre>";
$bSucc = $oOP->SaveObject($oUser);
echo "<div>".($bSucc ? 'saved' : 'error')."</div>";
if(!$bSucc) echo "<pre>".$oOP->GetDB()->GetLastErrorString()."</pre>";
echo "<pre>\$oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load by value - load object created above -> Object Pool hit
echo "<h3>Load by value 2</h3>";
$xVal = $oUser->GetProperty('user');
echo "<pre>\$aoUsers = \$oOP->LoadObjectsByValue(".$oClass->GetName().", 'user', $xVal);</pre>";
$aoUsers = $oOP->LoadObjectsByValue($oClass, 'user', $xVal);
echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Remove from pool - still that one object
echo "<h3>Remove from pool</h3>";
echo "<pre>\$bSucc = \$oOP->RemObjectFromPool(\$oUser);</pre>";
$bSucc = $oOP->RemObjectFromPool($oUser);
echo "<pre>\$oUser: [".gettype($oUser)."]".AdjustedPrintR($oUser)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load by value - that object again
echo "<h3>Load by value 3</h3>";
$xVal = $oUser->GetProperty('user');
echo "<pre>\$aoUsers = \$oOP->LoadObjectsByValue(".$oClass->GetName().", 'user', $xVal);</pre>";
$aoUsers = $oOP->LoadObjectsByValue($oClass, 'user', $xVal);
echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Delete that object from DB
echo "<h3>Delete object by ID</h3>";
echo "<pre>\$oOP->DeleteObject(".$oClass->GetName().", ".$oUser->GetId().");</pre>";
$bSucc = $oOP->DeleteObject($oClass, $oUser->GetId());
if(!$bSucc) echo '<div style="font-color: red;">Delete failed. Error: '.$oOP->GetError()."</pre>";
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
// Load all objects
echo "<h3>Load all objects</h3>";
echo "<pre>\$aoUsers = \$oOP->LoadObjects(".$oClass->GetName().");</pre>";
$aoUsers = $oOP->LoadObjects($oClass);
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
//echo "<pre>\$aoUsers: [".gettype($aoUsers)."]".AdjustedPrintR($aoUsers)."</pre>";
// M : N relation
$oClassUser = $oClass;
echo "<h2>M : N Relation</h2>";
echo "<div>\$oClassDoor = \$oOP->CreateClassByTable('cObjectPersistence_TestClass_Door', 'ap_doors');</div>";
$oClassDoor = $oOP->CreateClassByTable('cObjectPersistence_TestClass_Door', 'ap_doors');
file_put_contents('oClassDoor.txt', AdjustedPrintR($oClassDoor));///
echo "<div>\$oClassDoor->IsSuitableForMnRelationSide(): ".(int)$oClassDoor->IsSuitableForMnRelationSide()."</div>";
echo "<div>\$oClassUser->IsSuitableForMnRelationSide(): ".(int)$oClassUser->IsSuitableForMnRelationSide()."</div>";
echo "<div>\$oClassKey = \$oOP->CreateClassByTable('cObjectPersistence_TestClass_Key', 'ap_keys');</div>";
$oClassKey = $oOP->CreateClassByTable('cObjectPersistence_TestClass_Key', 'ap_keys');
file_put_contents('oClassKey.txt', AdjustedPrintR($oClassKey));///
echo "\$oClassKey->IsSuitableForMnRelationGlue(): ".(int)$oClassKey->IsSuitableForMnRelationGlue();
// Settin'up
echo '<pre>$oOP->SetMnRelation($oClassUser, $oClassKey, $oClassDoor);</pre>';
$bSucc = $oOP->SetMnRelation($oClassUser, $oClassKey, $oClassDoor);
file_put_contents('oClassKey2.txt', AdjustedPrintR($oClassKey));///
if(!$bSucc) echo "<div>Error: ".$oOP->GetError()."</div>";
// Load objects by M : N relation
/*/ Determines the Class and the ID from the $oUser object.
echo "<pre>\$aoDoors = \$oOP->LoadObjectsByMnRelation(\$oUser, \$oClassKey, \$oClassDoor)</pre>";
$aoDoors = $oOP->LoadObjectsByMnRelation($oUser, $oClassKey, $oClassDoor);
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
echo "<pre>\$aoDoors: (".gettype($aoDoors).") ".AdjustedPrintR($aoDoors)."</pre>";
/*/ // The same with ID explicitly set to 10001
echo "<pre>\$aoDoors = \$oOP->LoadObjectsByMnRelation('cObjectPersistenceTestClass_User', \$oClassKey, \$oClassDoor, 10001)</pre>";
$aoDoors = $oOP->LoadObjectsByMnRelation('cObjectPersistenceTestClass_User', $oClassKey, $oClassDoor, 10001);
echo "<div>GetPoolCount(): ".$oOP->GetPoolCount()."</div>";
echo "<pre>\$aoDoors: (".gettype($aoDoors).") ".AdjustedPrintR($aoDoors)."</pre>";
// Multiple ID properties SQL for an object:
echo "<div>\$oClassDoor->GetIdPropertiesSql(\$aoDoors[0]): ".$oClassDoor->GetIdPropertiesSql($aoDoors[0])."</pre>";
$aoKeys = $oOP->LoadObjectsByValue('cObjectPersistence_TestClass_Key', 'id_user', 10001);
echo "<div>\$oClassKey->GetIdPropertiesSql(\$aoDoors[0]): ".$oClassKey->GetIdPropertiesSql($aoKeys[0])."</pre>";
if( $oOP->GetError() )
echo '<div style="color: red">Error from the past: '.$oOP->GetError()."</div>";