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>";