2 /** @package verysimple::Phreeze */
5 * import supporting libraries
7 require_once("Observable.php");
8 require_once("Criteria.php");
9 require_once("DataAdapter.php");
10 require_once("CacheRam.php");
11 require_once("CacheNoCache.php");
12 require_once("verysimple/IO/Includer.php");
15 * The Phreezer class is a factory for obtaining and working with Phreezable (persistable)
17 * The Phreezer is generally the starting point for the application where you
18 * will obtain one or more objects.
20 * @package verysimple::Phreeze
21 * @author VerySimple Inc.
22 * @copyright 1997-2008 VerySimple, Inc.
23 * @license http://www.gnu.org/licenses/lgpl.html LGPL
26 class Phreezer
extends Observable
29 * An associative array of DataAdapter objects, which can be
30 * specified using SelectAdapter
37 * The currently selected DataAdapter
44 * Render engine can hold any arbitrary object used to render views
49 public static $Version = '3.3.8 HEAD';
51 /** @var bool set to true to enable compatibility with phreeze 2.0 apps */
52 public static $COMPAT_VERSION_2 = false;
56 * @var int expiration time for query & value cache (in seconds) default = 5
57 * The default is a low value which will help only with floods of traffic, but
58 * will prevent stale data from appearing
60 public $ValueCacheTimeout = 5;
64 * @var int expiration time for single objects cache (in seconds)
65 * All individual save operations will update the cache so this can be a higher value
66 * as long as other non-phreeze applications are not also editing the database
67 * and you are not doing bulk query updates.
69 public $ObjectCacheTimeout = 300; // 5 minutes
73 * @var set to true to save each individual query object in the level-2 cache
74 * this can lead to a lot of save operations on the level-2 cahce that don't
75 * ever get read, so enable only if you know it will improve performance
77 public $CacheQueryObjectLevel2 = false;
81 * @var string path used for saving lock files to prevent cache stampedes
95 private $_level1Cache;
101 private $_level2Cache;
104 * If Phreeze is loaded from a .
105 * phar file, return the path of that file
106 * otherwise return empty string
110 static function PharPath()
112 return class_exists("Phar") ? Phar
::running() : '';
116 * Contructor initializes the object.
117 * The database connection is opened only when
120 * The ConnectionSetting parameter can be either a single connection setting, or
121 * an associative array. This allows switching among different database connections
122 * which can be referred to by their array key using Phreezer->SelectAdapter.
123 * Multiple connections can be used for example to read from a slave database
124 * and write to a master.
126 * One instantiate the DataAdapter will be set to whichever is the first
127 * connection in the list.
129 * If a single ConnectionSetting is supplied, it will be assigned the key "default"
133 * ConnectionSetting || Associative Array of ConnectionSetting objects
134 * @param Observable $observer
136 public function __construct($csetting, $observer = null)
138 $this->_mapCache
= new CacheRam();
139 $this->_level1Cache
= new CacheRam();
140 $this->_level2Cache
= new CacheNoCache();
143 parent
::AttachObserver($observer);
146 $this->Observe("Phreeze Instantiated", OBSERVE_DEBUG
);
148 $csettings = is_array($csetting) ?
$csetting : array (
149 'default' => $csetting
152 $this->DataAdapters
= array ();
153 foreach ($csettings as $key => $connection) {
154 $this->DataAdapters
[$key] = new DataAdapter($connection, $observer, null, $key);
157 $this->SelectAdapter();
161 * SelectAdapter will change the DataAdapter, allowing the application
162 * to query from multiple data sources.
163 * The connection strings for
164 * each database should be passed in an array during construction of
165 * the Phreezer object.
167 * Once this method is called, all DB calls will be made to this connection
168 * until another adapter is selected.
171 * @return DataAdapter the selected DataAdapter
173 public function SelectAdapter($key = null)
176 $this->Observe("Selecting DataAdapter with key '$key'", OBSERVE_DEBUG
);
177 if (! array_key_exists($key, $this->DataAdapters
)) {
178 throw new Exception("No DataAdapter with key '$key' is available");
181 $this->DataAdapter
= $this->DataAdapters
[$key];
183 $this->Observe("Selecting Default DataAdapter", OBSERVE_DEBUG
);
184 $adapters = array_values($this->DataAdapters
);
185 $this->DataAdapter
= $adapters [0];
188 return $this->DataAdapter
;
192 * Sets a cache provider for the level 1 cache
194 * @param ICache $cache
196 private function SetLevel1CacheProvider(ICache
$cache)
198 $this->_level1Cache
= $cache;
202 * Sets a cache provider for the level 1 cache
204 * @param ICache $cache
206 public function SetLevel2CacheProvider(ICache
$cache, $lockFilePath = "")
208 $this->_level2Cache
= $cache;
209 $this->LockFilePath
= $lockFilePath;
213 * ValueCache is a utility method allowing any object or value to
214 * be stored in the cache.
215 * The timout is specified by
216 * ValueCacheTimeout. This
219 * @param variant $val
221 * int cache timeout (in seconds) default = Phreezer->ValueCacheTimeout. set to zero for no cache
222 * @return bool true if cache was set, false if not
224 public function SetValueCache($key, $val, $timeout = null)
226 if (is_null($timeout)) {
227 $timeout = $this->ValueCacheTimeout
;
234 if (strlen($key) > 250) {
235 $key = substr($key, 0, 150) . md5($key);
238 $this->_level1Cache
->Set(md5($key), $val, 0, $timeout);
239 return $this->_level2Cache
->Set($key, $val, 0, $timeout);
243 * Retreives an object or value that was persisted using SetValueCache
248 public function GetValueCache($key)
250 // save the trouble of retrieving the cache if it is not enabled
251 if ($this->ValueCacheTimeout
<= 0) {
255 if (strlen($key) > 250) {
256 $key = substr($key, 0, 150) . md5($key);
259 $obj = $this->_level1Cache
->Get(md5($key));
260 return $obj ?
$obj : $this->_level2Cache
->Get($key);
264 * Deletes a value from the cache
266 * @param string $objectclass
269 public function DeleteCache($objectclass, $id)
271 $this->_level1Cache
->Delete($objectclass . "_" . $id);
272 $this->_level2Cache
->Delete($objectclass . "_" . $id);
273 $this->Observe("Deleted TYPE='$objectclass' ID='$id' from Cache", OBSERVE_DEBUG
);
277 * Sets value in the cache
279 * @param string $objectclass
281 * @param Phreezable $val
282 * @param bool $includeCacheLevel2
283 * true = cache both level 1 and 2. false = cache only level 1. (default true)
285 * int optionally override the default cache timeout of Phreezer->ObjectCacheTimeout (in seconds)
287 public function SetCache($objectclass, $id, Phreezable
$val, $includeCacheLevel2 = true, $timeout = null)
289 if (is_null($timeout)) {
290 $timeout = $this->ObjectCacheTimeout
;
293 if ($val->NoCache() ||
$timeout <= 0) {
297 // if the object hasn't changed at level 1, then supress the cache update
298 $obj = $this->_level1Cache
->Get($objectclass . "_" . $id);
300 if ($obj && $obj->serialize() == $val->serialize()) {
301 $this->Observe("TYPE='$objectclass' ID='$id' level 1 cache has not changed. SetCache was supressed", OBSERVE_DEBUG
);
305 $this->_level1Cache
->Set($objectclass . "_" . $id, $val, $timeout);
307 // cache level 2 only if specified
308 if ($includeCacheLevel2) {
309 $this->_level2Cache
->Set($objectclass . "_" . $id, $val, $timeout);
314 * Retrieves a value from the cache
316 * @param string $objectclass
320 public function GetCache($objectclass, $id)
322 if ($this->ObjectCacheTimeout
<= 0) {
326 $cachekey = $objectclass . "_" . $id;
328 // include the model so any serialized classes will not throw an exception
329 $this->IncludeModel($objectclass);
331 // see if this object was cached in the level 1 cache
332 $obj = $this->_level1Cache
->Get($cachekey);
335 $this->Observe("Retrieved TYPE='$objectclass' ID='$id' from 1st Level Cache", OBSERVE_DEBUG
);
337 if (! $obj->IsLoaded()) {
338 $obj->Refresh($this);
344 // try the level 2 cahce
345 $obj = $this->_level2Cache
->Get($cachekey);
348 $this->Observe("Retrieved TYPE='$objectclass' ID='$id' from 2nd Level Cache", OBSERVE_DEBUG
);
349 $obj->Refresh($this);
352 // we just got this from level 2, but it wasn't in level 1 so let's save it in level 1 for
353 $this->_level1Cache
->Set($cachekey, $obj);
358 $this->Observe("No L1/L2 Cache for TYPE='$objectclass' ID='$id'", OBSERVE_DEBUG
);
359 // $this->Observe("KEYS =" . serialize($this->_level1Cache->GetKeys()) ,OBSERVE_DEBUG);
364 * Override of the base AttachObserver so that when an observer is attached, it
365 * will also be attached to all child objects.
366 * Note that some initialization
367 * messages won't be observed unless you provide it in the Phreezer constructor
369 public function AttachObserver($observer)
371 parent
::AttachObserver($observer);
372 foreach ($this->DataAdapters
as $adapter) {
373 $adapter->AttachObserver($observer);
378 * Phreezer::Compare is used internally by Phreezer::Sort
386 static function Compare($a, $b)
388 return strcmp($a->ToString(), $b->ToString());
392 * Sort an array of Phreezable objects.
393 * ToString() is used as the sort
394 * key. You must implmement ToString on your sortable objects in order
395 * for Phreezer::Sort to be effective
397 * @param array $objects
400 static function Sort(&$objects)
402 usort($objects, array (
409 * Get one instance of an object based on criteria.
410 * If multiple records
411 * are found, only the first is returned. If no matches are found,
412 * an exception is thrown
415 * @param string $objectclass
416 * the type of object that will be queried
417 * @param Criteria $criteria
418 * a Criteria object to limit results
419 * @param bool $crash_if_multiple_found
420 * default value = true
422 * int cache timeout (in seconds). Default is Phreezer->ValueCacheTimeout. Set to 0 for no cache
425 public function GetByCriteria($objectclass, $criteria, $crash_if_multiple_found = true, $cache_timeout = null)
427 if (is_null($cache_timeout)) {
428 $cache_timeout = $this->ValueCacheTimeout
;
431 if (strlen($objectclass) < 1) {
432 throw new Exception("\$objectclass argument is required");
436 $objs = $this->Query($objectclass, $criteria, $cache_timeout)->ToObjectArray();
438 if (count($objs) == 0) {
439 require_once("NotFoundException.php");
440 throw new NotFoundException("$objectclass with specified criteria not found");
443 if ($crash_if_multiple_found && count($objs) > 1) {
444 throw new Exception("More than one $objectclass with specified criteria was found");
453 * Query for a specific type of object
456 * @param string $objectclass
457 * the type of object that your DataSet will contain
458 * @param Criteria $criteria
459 * a Criteria object to limit results
461 * int cache timeout (in seconds). Default is Phreezer->ValueCacheTimeout. Set to 0 for no cache
464 public function Query($objectclass, $criteria = null, $cache_timeout = null)
466 if (is_null($cache_timeout)) {
467 $cache_timeout = $this->ValueCacheTimeout
;
470 if (strlen($objectclass) < 1) {
471 throw new Exception("\$objectclass argument is required");
474 // if criteria is null, then create a generic one
475 if (is_null($criteria)) {
476 $criteria = new Criteria();
479 // see if this object has a custom query designated
480 $custom = $this->GetCustomQuery($objectclass, $criteria);
486 $this->Observe("Using Custom Query", OBSERVE_DEBUG
);
489 // the counter query may be blank, in which case DataSet will generate one
490 $count_sql = $this->GetCustomCountQuery($objectclass, $criteria);
492 // the first-level fieldmaps should be from the primary table
493 $fms = $this->GetFieldMaps($objectclass);
495 // the query builder will handle creating the SQL for us
496 require_once("QueryBuilder.php");
497 $builder = new QueryBuilder($this);
498 $builder->RecurseFieldMaps($objectclass, $fms);
500 $sql = $builder->GetSQL($criteria);
502 $count_sql = $builder->GetCountSQL($criteria);
505 require_once("DataSet.php");
506 $ds = new DataSet($this, $objectclass, $sql, $cache_timeout);
507 $ds->CountSQL
= $count_sql;
508 $ds->UnableToCache
= $cache_timeout === 0;
514 * Get one instance of an object based on it's primary key value
517 * @param string $objectclass
520 * the value of the primary key
522 * int cache timeout (in seconds). Default is Phreezer->ObjectCacheTimeout. Set to 0 for no cache
525 public function Get($objectclass, $id, $cache_timeout = null)
527 if (is_null($cache_timeout)) {
528 $cache_timeout = $this->ObjectCacheTimeout
;
531 if (strlen($objectclass) < 1) {
532 throw new Exception("\$objectclass argument is required");
535 if (strlen($id) < 1) {
536 throw new Exception("\$id argument is required for $objectclass");
539 // see if this object was cached & if so return it
540 $obj = $cache_timeout == 0 ?
null : $this->GetCache($objectclass, $id);
545 $pkm = $this->GetPrimaryKeyMap($objectclass);
548 throw new Exception("Table for '$objectclass' has no primary key");
551 $criteria = new Criteria();
552 $criteria->PrimaryKeyField
= "`" . $pkm->TableName
. "`.`" . $pkm->ColumnName
. "`";
553 $criteria->PrimaryKeyValue
= $id;
555 $ds = $this->Query($objectclass, $criteria);
558 $ds->UnableToCache
= false;
560 if (! $obj = $ds->Next()) {
561 require_once("NotFoundException.php");
562 throw new NotFoundException("$objectclass with primary key of $id not found");
565 // cache the object for future use
566 $this->SetCache($objectclass, $id, $obj, $cache_timeout);
572 * Persist an object to the data store.
573 * An insert or update will be executed based
574 * on whether the primary key has a value. use $form_insert to override this
575 * in the case of a primary key that is not an auto_increment
579 * the object to persist
580 * @param bool $force_insert
582 * @return int the auto_increment id (insert) or the number of records updated (update)
584 public function Save($obj, $force_insert = false)
586 $objectclass = get_class($obj);
587 $fms = $this->GetFieldMaps($objectclass);
589 $pk = $obj->GetPrimaryKeyName();
591 $table = $fms [$pk]->TableName
;
592 $pkcol = $fms [$pk]->ColumnName
;
595 $pk_is_auto_insert = strlen($id) == 0;
597 // if there is no value for the primary key, this is an insert
598 $is_insert = $force_insert ||
$pk_is_auto_insert;
600 // fire the OnSave event in case the object needs to prepare itself
601 // if OnSave returns false, then don't proceed with the save
602 $this->Observe("Firing " . get_class($obj) . "->OnSave($is_insert)", OBSERVE_DEBUG
);
603 if (! $obj->OnSave($is_insert)) {
604 $this->Observe("" . get_class($obj) . "->OnSave($is_insert) returned FALSE. Exiting without saving", OBSERVE_WARN
);
613 // remove this class from the cache before saving
614 $this->DeleteCache($objectclass, $id);
616 $sql = "update `$table` set ";
618 foreach ($fms as $fm) {
619 if ((! $fm->IsPrimaryKey
) && $fm->FieldType
!= FM_CALCULATION
) {
620 $prop = $fm->PropertyName
;
624 $sql .= $delim . "`" . $fm->ColumnName
. "` = " . $this->GetQuotedSql($val);
625 } catch (Exception
$ex) {
626 throw new Exception("Error escaping property '$prop'. value could not be converted to string");
633 $sql .= " where $pkcol = '" . $this->Escape($id) . "'";
635 $returnval = $this->DataAdapter
->Execute($sql);
637 $obj->OnUpdate(); // fire OnUpdate event
640 $sql = "insert into `$table` (";
642 foreach ($fms as $fm) {
643 // we don't want to include the primary key if this is an auto-increment table
644 if ((! $fm->IsPrimaryKey
) ||
$force_insert) {
645 // calculated fields are not directly bound to a column and do not get persisted
646 if ($fm->FieldType
!= FM_CALCULATION
) {
647 $prop = $fm->PropertyName
;
649 $sql .= $delim . "`" . $fm->ColumnName
. "`";
655 $sql .= ") values (";
658 foreach ($fms as $fm) {
659 // use the save logic inserting values as with the column names above
660 if ((! $fm->IsPrimaryKey
) ||
$force_insert) {
661 if ($fm->FieldType
!= FM_CALCULATION
) {
662 $prop = $fm->PropertyName
;
666 $sql .= $delim . ' ' . $this->GetQuotedSql($val);
667 } catch (Exception
$ex) {
668 throw new Exception("Error escaping property '$prop'. value could not be converted to string");
678 // for the insert we also need to get the insert id of the primary key
679 $returnval = $this->DataAdapter
->Execute($sql);
680 if ($pk_is_auto_insert) {
681 $returnval = $this->DataAdapter
->GetLastInsertId();
682 $obj->$pk = $returnval;
685 $obj->OnInsert(); // fire OnInsert event
692 * Delete the given object from the data store
696 * the object to delete
698 public function Delete($obj)
700 $objectclass = get_class($obj);
702 if (! $obj->OnBeforeDelete()) {
703 $this->Observe("Delete was cancelled because OnBeforeDelete did not return true");
707 $fms = $this->GetFieldMaps($objectclass);
709 $pk = $obj->GetPrimaryKeyName();
711 $table = $fms [$pk]->TableName
;
712 $pkcol = $fms [$pk]->ColumnName
;
714 $sql = "delete from `$table` where `$pkcol` = '" . $this->Escape($id) . "'";
715 $returnval = $this->DataAdapter
->Execute($sql);
718 $this->DeleteCache($objectclass, $id);
720 $obj->OnDelete(); // fire OnDelete event
726 * Delete all objects from the datastore used by the given object
730 * the object to delete
732 public function DeleteAll($obj)
734 $fms = $this->GetFieldMaps(get_class($obj));
735 $pk = $obj->GetPrimaryKeyName();
736 $table = $fms [$pk]->TableName
;
738 $sql = "delete from `$table`";
739 $returnval = $this->DataAdapter
->Execute($sql);
740 $obj->OnDelete(); // fire OnDelete event
745 * Returns all FieldMaps for the given object class
748 * @param string $objectclass
749 * the type of object that your DataSet will contain
750 * @return Array of FieldMap objects
752 public function GetFieldMaps($objectclass)
754 // this is a temporary ram cache
755 $fms = $this->_mapCache
->Get($objectclass . "FieldMaps");
760 $this->IncludeModel($objectclass);
762 if (! class_exists($objectclass . "Map")) {
763 throw new Exception($objectclass . " must either implement GetCustomQuery or '" . $objectclass . "Map' class must exist in the include path.");
766 $fms = call_user_func(array (
767 $objectclass . "Map",
771 $this->_mapCache
->Set($objectclass . "FieldMaps", $fms);
776 * Returns the custom query for the given object class if it is defined
779 * @param string $objectclass
780 * the type of object that your DataSet will contain
781 * @return Array of FieldMap objects
783 public function GetCustomQuery($objectclass, $criteria)
785 $this->IncludeModel($objectclass);
786 $sql = call_user_func(array (
794 * Returns the custom "counter" query for the given object class if it is defined
797 * @param string $objectclass
798 * the type of object that your DataSet will contain
799 * @return Array of FieldMap objects
801 public function GetCustomCountQuery($objectclass, $criteria)
803 $this->IncludeModel($objectclass);
804 $sql = call_user_func(array (
806 "GetCustomCountQuery"
810 static $cnt = 0; // used for debugging php memory errors due to circular references
813 * Returns all KeyMaps for the given object class
816 * @param string $objectclass
818 * @return Array of KeyMap objects
820 public function GetKeyMaps($objectclass)
822 // TODO: if a php memory error occurs within this method, uncomment this block to debug
824 * if (Phreezer::$cnt++ > 500)
826 * throw new Exception("A sanity limit was exceeded when recursing KeyMaps for `$objectclass`. Please check your Map for circular joins.");
831 // this is a temporary ram cache
832 $kms = $this->_mapCache
->Get($objectclass . "KeyMaps");
837 $this->IncludeModel($objectclass);
838 if (! class_exists($objectclass . "Map")) {
839 throw new Exception("Class '" . $objectclass . "Map' is not defined.");
842 $kms = call_user_func(array (
843 $objectclass . "Map",
847 $this->_mapCache
->Set($objectclass . "KeyMaps", $kms);
852 * Return specific FieldMap for the given object class with the given name
855 * @param string $objectclass
857 * @param string $propertyname
858 * the name of the property
859 * @return Array of FieldMap objects
861 public function GetFieldMap($objectclass, $propertyname)
863 $fms = $this->GetFieldMaps($objectclass);
864 return $fms [$propertyname];
868 * Return specific KeyMap for the given object class with the given name
871 * @param string $objectclass
873 * @param string $keyname
874 * the name of the key
875 * @return Array of KeyMap objects
877 public function GetKeyMap($objectclass, $keyname)
879 $kms = $this->GetKeyMaps($objectclass);
880 return $kms [$keyname];
884 * Returns the name of the DB column associted with the given property
887 * @param string $objectclass
889 * @param string $propertyname
890 * the name of the property
891 * @return string name of the DB Column
893 public function GetColumnName($objectclass, $propertyname)
895 $fm = $this->GetFieldMap($objectclass, $propertyname);
896 return $fm->ColumnName
;
900 * Returns the name of the DB Table associted with the given property
903 * @param string $objectclass
905 * @param string $propertyname
906 * the name of the property
907 * @return string name of the DB Column
909 public function GetTableName($objectclass, $propertyname)
911 $fm = $this->GetFieldMap($objectclass, $propertyname);
912 return $fm->TableName
;
916 * Return the KeyMap for the primary key for the given object class
919 * @param string $objectclass
921 * @return KeyMap object
923 public function GetPrimaryKeyMap($objectclass)
925 $fms = $this->GetFieldMaps($objectclass);
926 foreach ($fms as $fm) {
927 if ($fm->IsPrimaryKey
) {
934 * Query for a child objects in a one-to-many relationship
937 * @param Phreezable $parent
939 * @param string $keyname
940 * The name of the key representing the relationship
941 * @return Criteria $criteria a Criteria object to limit the results
943 public function GetOneToMany($parent, $keyname, $criteria)
946 // get the keymap for this child relationship
947 $km = $this->GetKeyMap(get_class($parent), $keyname);
949 // we need the value of the foreign key. (ex. to get all orders for a customer, we need Customer.Id)
950 $parent_prop = $km->KeyProperty
;
951 $key_value = $parent->$parent_prop;
954 // if no criteria was specified, then create a generic one. we can specify SQL
955 // code in the constructor, but we have to translate the properties into column names
956 $foreign_table = $this->GetTableName($km->ForeignObject
, $km->ForeignKeyProperty
);
957 $foreign_column = $this->GetColumnName($km->ForeignObject
, $km->ForeignKeyProperty
);
958 $criteria = new Criteria("`" . $foreign_table . "`.`" . $foreign_column . "` = '" . $this->Escape($key_value) . "'");
960 // ensure that the criteria passed in will filter correctly by foreign key
961 $foreign_prop = $km->ForeignKeyProperty
;
963 // this is only for backwards compatibility with phreeze 2.0 apps
964 if (self
::$COMPAT_VERSION_2) {
965 $criteria->$foreign_prop = $key_value;
968 // the current criteria "Equals" format "FieldName_Equals"
969 $foreign_prop .= "_Equals";
970 $criteria->$foreign_prop = $key_value;
972 // if this criteria has any or criterias attached, we need to set the foreign key to these
973 // as well or else we'll get unexpected results
974 foreach ($criteria->GetOrs() as $oc) {
975 $oc->$foreign_prop = $key_value;
979 return $this->Query($km->ForeignObject
, $criteria);
983 * Query for a parent object in a many-to-one relationship
986 * @param Phreezable $parent
988 * @param string $keyname
989 * The name of the key representing the relationship
990 * @return Phreezable object an object of the type specified by the KeyMap
992 public function GetManyToOne($parent, $keyname)
994 // get the keymap for this child relationship
995 $km = $this->GetKeyMap(get_class($parent), $keyname);
997 // we need the value of the foreign key. (ex. to get all orders for a customer, we need Customer.Id)
998 // we also need to know the class of the object we're retrieving because if it's cached, we need to
999 // make sure the model file is loaded
1000 $objectclass = $km->ForeignObject
;
1001 $parent_prop = $km->KeyProperty
;
1002 $key_value = $parent->$parent_prop;
1004 // get this object Get uses caching so we don't need to bother
1005 $obj = $this->Get($km->ForeignObject
, $key_value);
1011 * Dynamically override the LoadType for a KeyMap.
1012 * This is useful for
1013 * eager fetching for a particular query. One set, this configuration
1014 * will be used until the end of the page context, or it is changed.
1017 * @param string $objectclass
1018 * The name of the object class
1019 * @param string $keyname
1020 * The unique id of the KeyMap in the objects KeyMaps collection
1021 * @param int $load_type
1022 * (optional) KM_LOAD_INNER | KM_LOAD_EAGER | KM_LOAD_LAZY (default is KM_LOAD_EAGER)
1024 public function SetLoadType($objectclass, $keyname, $load_type = KM_LOAD_EAGER
)
1026 $this->GetKeyMap($objectclass, $keyname)->LoadType
= $load_type;
1030 * Utility method that calls DataAdapter::Escape($val)
1032 * @param variant $val
1036 public function Escape($val)
1038 return DataAdapter
::Escape($val);
1042 * Utility method that calls DataAdapter::GetQuotedSql($val)
1044 * @param variant $val
1048 private function GetQuotedSql($val)
1050 return DataAdapter
::GetQuotedSql($val);
1054 * If the type is not already defined, attempts to require_once the definition.
1055 * If the Model file cannot be located, an exception is thrown
1058 * @param string $objectclass
1059 * The name of the object class
1061 public function IncludeModel($objectclass)
1063 Includer
::RequireClass($objectclass, array (