From f6fac5cc2f679a6e93a39ea4127f58e438a583c5 Mon Sep 17 00:00:00 2001 From: wei <> Date: Thu, 1 Nov 2007 04:20:14 +0000 Subject: Refactored ActiveRecord: removed object registry, fixed relationship casing problems. --- .gitattributes | 1 - .../Relations/TActiveRecordBelongsTo.php | 20 +- .../Relations/TActiveRecordHasMany.php | 12 +- .../Relations/TActiveRecordHasManyAssociation.php | 10 +- .../ActiveRecord/Relations/TActiveRecordHasOne.php | 17 +- .../Relations/TActiveRecordRelation.php | 2 +- .../Relations/TActiveRecordRelationContext.php | 3 +- framework/Data/ActiveRecord/TActiveRecord.php | 173 ++++++++++++--- .../Data/ActiveRecord/TActiveRecordManager.php | 24 +- .../ActiveRecord/TActiveRecordStateRegistry.php | 243 --------------------- .../source/prado/activecontrols/inlineeditor.js | 4 +- .../ActiveRecord/ForeignKeyTestCase.php | 1 - .../ActiveRecord/MultipleForeignKeyTestCase.php | 17 +- 13 files changed, 183 insertions(+), 344 deletions(-) delete mode 100644 framework/Data/ActiveRecord/TActiveRecordStateRegistry.php diff --git a/.gitattributes b/.gitattributes index e4e7fdb3..0c8dc975 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2028,7 +2028,6 @@ framework/Data/ActiveRecord/TActiveRecordConfig.php -text framework/Data/ActiveRecord/TActiveRecordCriteria.php -text framework/Data/ActiveRecord/TActiveRecordGateway.php -text framework/Data/ActiveRecord/TActiveRecordManager.php -text -framework/Data/ActiveRecord/TActiveRecordStateRegistry.php -text framework/Data/Common/IbmDb2/TIbmColumnMetaData.php -text framework/Data/Common/IbmDb2/TIbmMetaData.php -text framework/Data/Common/IbmDb2/TIbmMetaDataInspector.php -text diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php index c030f2d2..565070c1 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php @@ -123,20 +123,16 @@ class TActiveRecordBelongsTo extends TActiveRecordRelation { $obj = $this->getContext()->getSourceRecord(); $fkObject = $obj->getColumnValue($this->getContext()->getProperty()); - $registry = $fkObject->getRecordManager()->getObjectStateRegistry(); - if($registry->shouldPersistObject($fkObject)) + if($fkObject!==null) { - if($fkObject!==null) - { - $fkObject->save(); - $source = $this->getSourceRecord(); - $fkeys = $this->findForeignKeys($source, $fkObject); - foreach($fkeys as $srcKey => $fKey) - $source->setColumnValue($srcKey, $fkObject->getColumnValue($fKey)); - return true; - } + $fkObject->save(); + $source = $this->getSourceRecord(); + $fkeys = $this->findForeignKeys($source, $fkObject); + foreach($fkeys as $srcKey => $fKey) + $source->setColumnValue($srcKey, $fkObject->getColumnValue($fKey)); + return true; } - return true; + return false; } } diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php index f7426862..382d9789 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php @@ -88,7 +88,7 @@ class TActiveRecordHasMany extends TActiveRecordRelation /** * @return array foreign key field names as key and object properties as value. * @since 3.1.2 - */ + */ public function getRelationForeignKeys() { $fkObject = $this->getContext()->getForeignRecordFinder(); @@ -107,16 +107,12 @@ class TActiveRecordHasMany extends TActiveRecordRelation if(($total = count($fkObjects))> 0) { $source = $this->getSourceRecord(); - $registry = $source->getRecordManager()->getObjectStateRegistry(); $fkeys = $this->findForeignKeys($fkObjects[0], $source); for($i=0;$i<$total;$i++) { - if($registry->shouldPersistObject($fkObjects[$i])) - { - foreach($fkeys as $fKey => $srcKey) - $fkObjects[$i]->setColumnValue($fKey, $source->getColumnValue($srcKey)); - $success = $fkObjects[$i]->save() && $success; - } + foreach($fkeys as $fKey => $srcKey) + $fkObjects[$i]->setColumnValue($fKey, $source->getColumnValue($srcKey)); + $success = $fkObjects[$i]->save() && $success; } } return $success; diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php index 564d3d22..bcda962c 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php @@ -189,7 +189,6 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation { $criteria = $this->getCriteria(); $finder = $this->getContext()->getForeignRecordFinder(); - $registry = $finder->getRecordManager()->getObjectStateRegistry(); $type = get_class($finder); $command = $this->createCommand($criteria, $foreignKeys,$indexValues,$sourceKeys); $srcProps = array_keys($sourceKeys); @@ -201,7 +200,6 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation unset($row[$column]); $obj = $this->createFkObject($type,$row,$foreignKeys); $collections[$hash][] = $obj; - $registry->registerClean($obj); } $this->setResultCollection($results, $collections, array_values($sourceKeys)); } @@ -214,7 +212,7 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation */ protected function createFkObject($type,$row,$foreignKeys) { - $obj = new $type($row); + $obj = TActiveRecord::createRecordInstance($type, $row, TActiveRecord::STATE_LOADED); if(count($this->_association_columns) > 0) { $i=0; @@ -309,13 +307,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation if(($total = count($fkObjects))> 0) { $source = $this->getSourceRecord(); - $registry = $source->getRecordManager()->getObjectStateRegistry(); $builder = $this->getAssociationTableCommandBuilder(); for($i=0;$i<$total;$i++) - { - if($registry->shouldPersistObject($fkObjects[$i])) - $success = $fkObjects[$i]->save() && $success; - } + $success = $fkObjects[$i]->save() && $success; return $this->updateAssociationTable($obj, $fkObjects, $builder) && $success; } return $success; diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php index e5a36659..49119965 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php @@ -100,7 +100,7 @@ class TActiveRecordHasOne extends TActiveRecordRelation $fkObjects = $this->findForeignObjects($fields,$indexValues); $this->populateResult($results,$properties,$fkObjects,$fields); } - + /** * @return array foreign key field names as key and object properties as value. * @since 3.1.2 @@ -135,16 +135,11 @@ class TActiveRecordHasOne extends TActiveRecordRelation public function updateAssociatedRecords() { $fkObject = $this->getContext()->getPropertyValue(); - $registry = $fkObject->getRecordManager()->getObjectStateRegistry(); - if($registry->shouldPersistObject($fkObject)) - { - $source = $this->getSourceRecord(); - $fkeys = $this->findForeignKeys($fkObject, $source); - foreach($fkeys as $fKey => $srcKey) - $fkObject->setColumnValue($fKey, $source->getColumnValue($srcKey)); - return $fkObject->save(); - } - return true; + $source = $this->getSourceRecord(); + $fkeys = $this->findForeignKeys($fkObject, $source); + foreach($fkeys as $fKey => $srcKey) + $fkObject->setColumnValue($fKey, $source->getColumnValue($srcKey)); + return $fkObject->save(); } } diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php index 5bde4898..63e182ca 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php @@ -162,7 +162,7 @@ abstract class TActiveRecordRelation $ids=array(); foreach($properties as $property) $ids[] = is_object($obj) ? $obj->getColumnValue($property) : $obj[$property]; - return sprintf('%x',crc32(serialize($ids))); + return serialize($ids); } /** diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php index 8bc4362f..d6f86a9a 100644 --- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php +++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php @@ -182,8 +182,9 @@ class TActiveRecordRelationContext public function updateAssociatedRecords($updateBelongsTo=false) { $success=true; - foreach($this->_record->getRelations() as $property=>$relation) + foreach($this->_record->getRelations() as $data) { + list($property, $relation) = $data; $belongsTo = $relation[0]==TActiveRecord::BELONGS_TO; if(($updateBelongsTo && $belongsTo) || (!$updateBelongsTo && !$belongsTo)) { diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php index f5d73582..4bbee046 100644 --- a/framework/Data/ActiveRecord/TActiveRecord.php +++ b/framework/Data/ActiveRecord/TActiveRecord.php @@ -108,6 +108,27 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext'); * fetched in a lazy way, which avoids unnecessary overhead if the foreign objects are not accessed * at all. * + * Since v3.1.2, new events OnInsert, OnUpdate and OnDelete are available. + * The event OnInsert, OnUpdate and OnDelete methods are executed before + * inserting, updating, and deleting the current record, respectively. You may override + * these methods; a TActiveRecordChangeEventParameter parameter is passed to these methods. + * The property {@link TActiveRecordChangeEventParameter::setIsValid IsValid} of the parameter + * can be set to false to prevent the change action to be executed. This can be used, + * for example, to validate the record before the action is executed. For example, + * in the following the password property is hashed before a new record is inserted. + * + * class UserRecord extends TActiveRecord + * { + * function OnInsert($param) + * { + * //parent method should be called to raise the event + * parent::OnInsert($param); + * $this->nounce = md5(time()); + * $this->password = md5($this->password.$this->nounce); + * } + * } + * + * * @author Wei Zhuo * @version $Id$ * @package System.Data.ActiveRecord @@ -120,6 +141,16 @@ abstract class TActiveRecord extends TComponent const HAS_MANY='HAS_MANY'; const MANY_TO_MANY='MANY_TO_MANY'; + const STATE_NEW=0; + const STATE_LOADED=1; + const STATE_DELETED=2; + + /** + * @var integer object state: 0 = new, 1 = loaded, 2 = deleted. + * @since 3.1.2 + */ + private $_objectState=0; + /** * This static variable defines the column mapping. * The keys are physical column names as defined in database, @@ -177,11 +208,12 @@ abstract class TActiveRecord extends TComponent */ public function __construct($data=array(), $connection=null) { - $this->copyFrom($data); if($connection!==null) - $this->_connection=$connection; + $this->setDbConnection($connection); $this->setupColumnMapping(); $this->setupRelations(); + if(!empty($data)) //$data may be an object + $this->copyFrom($data); } /** @@ -242,7 +274,7 @@ abstract class TActiveRecord extends TComponent $class=new ReflectionClass($className); $relations=array(); foreach($class->getStaticPropertyValue('RELATIONS') as $key=>$value) - $relations[strtolower($key)]=$value; + $relations[strtolower($key)]=array($key,$value); self::$_relations[$className]=$relations; } } @@ -258,7 +290,7 @@ abstract class TActiveRecord extends TComponent if(!is_array($data)) throw new TActiveRecordException('ar_must_copy_from_array_or_object', get_class($this)); foreach($data as $name=>$value) - $this->$name = $value; + $this->setColumnValue($name,$value); return $this; } @@ -270,11 +302,7 @@ abstract class TActiveRecord extends TComponent public function getDbConnection() { if($this->_connection===null) - { - $this->setDbConnection(self::getRecordManager()->getDbConnection()); - if($this->_connection===null) //check it - throw new TActiveRecordException('ar_invalid_db_connection',get_class($this)); - } + return self::getRecordManager()->getDbConnection(); return $this->_connection; } @@ -367,19 +395,31 @@ abstract class TActiveRecord extends TComponent } /** - * Commit changes to the record, may insert, update or delete depending - * on the record state given in TObjectStateRegistery. + * Commit changes to the record: insert, update or delete depending on the object state. * @return boolean true if changes were made. */ protected function commitChanges() { - $registry = $this->getRecordManager()->getObjectStateRegistry(); $gateway = $this->getRecordGateway(); if(!$this->_readOnly) $this->_readOnly = $gateway->getRecordTableInfo($this)->getIsView(); if($this->_readOnly) throw new TActiveRecordException('ar_readonly_exception',get_class($this)); - return $registry->commit($this,$gateway); + $param = new TActiveRecordChangeEventParameter(); + switch($this->_objectState) + { + case self::STATE_NEW: + $this->onInsert($param); + return $param->getIsValid() ? $gateway->insert($this) : false; + case self::STATE_LOADED: + $this->onUpdate($param); + return $param->getIsValid() ? $gateway->update($this) : false; + case self::STATE_DELETED: + $this->onDelete($param); + return $param->getIsValid() ? $gateway->delete($this) : false; + default: + throw new TActiveRecordException('ar_invalid_state', get_class($this)); + } } /** @@ -389,8 +429,7 @@ abstract class TActiveRecord extends TComponent */ public function delete() { - $registry = $this->getRecordManager()->getObjectStateRegistry(); - $registry->registerRemoved($this); + $this->_objectState = self::STATE_DELETED; return $this->commitChanges(); } @@ -456,19 +495,22 @@ abstract class TActiveRecord extends TComponent { if(empty($data)) return null; - //create and populate the object + $obj = self::createRecordInstance($type, $data, self::STATE_LOADED); + return $obj; + } + + /** + * Create an instance of ActiveRecord class given by $type. + * This static method should only be used internally within core ActiveRecord classes. + */ + public static function createRecordInstance($type, $data=array(), $state=self::STATE_NEW) + { $obj = Prado::createComponent($type); - $tableInfo = $this->getRecordGateway()->getRecordTableInfo($obj); - foreach($data as $name=>$value) - $obj->setColumnValue($name,$value); - /* - foreach($tableInfo->getColumns()->getKeys() as $name) - { - if(isset($data[$name])) - $obj->setColumnValue($name,$data[$name]); - }*/ - $obj->_readOnly = $tableInfo->getIsView(); - $this->getRecordManager()->getObjectStateRegistry()->registerClean($obj); + $obj->_objectState=$state; + $tableInfo = $obj->getRecordGateway()->getRecordTableInfo($obj); + $obj->_readOnly=$tableInfo->getIsView(); + if(!empty($data)) + $obj->copyFrom($data); return $obj; } @@ -642,9 +684,9 @@ abstract class TActiveRecord extends TComponent * @param array method call arguments. * @return TActiveRecordRelation, null if the context or the handler doesn't exist */ - protected function getRelationHandler($property,$args=array()) + protected function getRelationHandler($name,$args=array()) { - if(($context=$this->getRelationContext($property)) !== null) + if(($context=$this->getRelationContext($name)) !== null) { $criteria = $this->getCriteria(count($args)>0 ? $args[0] : null, array_slice($args,1)); return $context->getRelationHandler($criteria); @@ -662,10 +704,10 @@ abstract class TActiveRecord extends TComponent * the active record relationships for given property, null if invalid relationship * @since 3.1.2 */ - protected function getRelationContext($property) + protected function getRelationContext($name) { - if(($relation=$this->getRelation($property))!==null) - return new TActiveRecordRelationContext($this,strtolower($property),$relation); + if(list($property, $relation) = $this->getRelation($name)) + return new TActiveRecordRelationContext($this,$property,$relation); else return null; } @@ -824,6 +866,36 @@ abstract class TActiveRecord extends TComponent $this->raiseEvent('OnExecuteCommand', $this, $param); } + /** + * Raised before the record attempt to insert its data into the database. + * To prevent the insert operation, set the TActiveRecordChangeEventParameter::IsValid parameter to false. + * @param TActiveRecordChangeEventParameter event parameter to be passed to the event handlers + */ + public function onInsert($param) + { + $this->raiseEvent('OnInsert', $this, $param); + } + + /** + * Raised before the record attempt to delete its data from the database. + * To prevent the insert operation, set the TActiveRecordChangeEventParameter::IsValid parameter to false. + * @param TActiveRecordChangeEventParameter event parameter to be passed to the event handlers + */ + public function onDelete($param) + { + $this->raiseEvent('OnDelete', $this, $param); + } + + /** + * Raised before the record attempt to update its data in the database. + * To prevent the insert operation, set the TActiveRecordChangeEventParameter::IsValid parameter to false. + * @param TActiveRecordChangeEventParameter event parameter to be passed to the event handlers + */ + public function onUpdate($param) + { + $this->raiseEvent('OnUpdate', $this, $param); + } + /** * Retrieves the column value according to column name. * This method is used internally. @@ -885,4 +957,41 @@ abstract class TActiveRecord extends TComponent return isset(self::$_relations[get_class($this)][strtolower($property)]); } } + +/** + * TActiveRecordChangeEventParameter class + * + * TActiveRecordChangeEventParameter encapsulates the parameter data for + * ActiveRecord change commit events that are broadcasted. The following change events + * may be raise: {@link TActiveRecord::OnInsert}, {@link TActiveRecord::OnUpdate} and + * {@link TActiveRecord::OnDelete}. The {@link setIsValid IsValid} parameter can + * be set to false to prevent the requested change event to be performed. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Data.ActiveRecord + * @since 3.1.2 + */ + +class TActiveRecordChangeEventParameter extends TEventParameter +{ + private $_isValid=true; + + /** + * @return boolean whether the event should be performed. + */ + public function getIsValid() + { + return $this->_isValid; + } + + /** + * @param boolean set to false to prevent the event. + */ + public function setIsValid($value) + { + $this->_isValid = TPropertyValue::ensureBoolean($value); + } +} + ?> \ No newline at end of file diff --git a/framework/Data/ActiveRecord/TActiveRecordManager.php b/framework/Data/ActiveRecord/TActiveRecordManager.php index ab6fe88d..3790773d 100644 --- a/framework/Data/ActiveRecord/TActiveRecordManager.php +++ b/framework/Data/ActiveRecord/TActiveRecordManager.php @@ -14,11 +14,10 @@ Prado::using('System.Data.TDbConnection'); Prado::using('System.Data.ActiveRecord.TActiveRecord'); Prado::using('System.Data.ActiveRecord.Exceptions.TActiveRecordException'); Prado::using('System.Data.ActiveRecord.TActiveRecordGateway'); -Prado::using('System.Data.ActiveRecord.TActiveRecordStateRegistry'); /** - * TActiveRecordManager provides the default DB connection, default object state - * registry, default active record gateway, and table meta data inspector. + * TActiveRecordManager provides the default DB connection, + * default active record gateway, and table meta data inspector. * * The default connection can be set as follows: * @@ -38,7 +37,6 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordStateRegistry'); */ class TActiveRecordManager extends TComponent { - private $_objectRegistry; private $_gateway; private $_meta=array(); private $_connection; @@ -90,24 +88,6 @@ class TActiveRecordManager extends TComponent return $instance; } - /** - * @return TActiveRecordStateRegistry record object registry. - */ - public function getObjectStateRegistry() - { - if(is_null($this->_objectRegistry)) - $this->_objectRegistry = $this->createObjectStateRegistry(); - return $this->_objectRegistry; - } - - /** - * @return TActiveRecordStateRegistry default object registry. - */ - protected function createObjectStateRegistry() - { - return new TActiveRecordStateRegistry(); - } - /** * @return TActiveRecordGateway record gateway. */ diff --git a/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php b/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php deleted file mode 100644 index 7a285274..00000000 --- a/framework/Data/ActiveRecord/TActiveRecordStateRegistry.php +++ /dev/null @@ -1,243 +0,0 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2007 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Data.ActiveRecord - */ - -/** - * Active record Unit of Work class and Identity Map. - * - * Maintains a list of objects affected by a business transaction and - * coordinates the writing out of changes and the resolution of concurrency problems. - * - * This registry keeps track of everything you do during a business transaction - * that can affect the database. When you're done, it figures out everything that - * needs to be done to alter the database as a result of your work. - * - * The object can only be in one of the four states: "new", "clean", "dirty" or "removed". - * A "new" object is one that is created not by loading the record from database. - * A "clean" object is one that is created by loading the record from datase. - * A "dirty" object is one that is marked as dirty or a "clean" object that has - * its internal state altered (done by using == object comparision). - * A "removed" object is one that is marked for deletion. - * - * See the "Active Record Object States.png" in the docs directory for state - * transition diagram. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Data.ActiveRecord - * @since 3.1 - */ -class TActiveRecordStateRegistry -{ - private $_cleanObjects=array(); - private $_removedObjects; - //private $_cachedObjects=array(); - /** - * Initialize the registry. - */ - public function __construct() - { - $this->_removedObjects = new TList; - } - - /** - * @return string hash of the data. - */ - protected function getObjectDataKey($data) - { - return sprintf('%x',crc32(serialize($data))); - } - - /** - * Ensure that object is not null. - */ - protected function assertNotNull($obj) - { - if(is_null($obj)) - throw new TActiveRecordException('ar_object_must_not_be_null'); - } - - /** - * Register the object for deletion, when the object invokes its delete() method - * the corresponding row in the database is deleted. - * @param TActiveRecord existing active record. - * @throws TActiveRecordException if object is null. - */ - public function registerRemoved($obj) - { - $this->assertNotNull($obj); - $found=false; - foreach($this->_cleanObjects as $i=>$cache) - { - if($cache[0]===$obj) - { - unset($this->_cleanObjects[$i]); - $found=true; - } - } - if(!$found) - throw new TActiveRecordException('ar_object_must_be_retrieved_before_delete'); - if(!$this->_removedObjects->contains($obj)) - $this->_removedObjects->add($obj); - } - - /** - * Register a clean object attached to a specific data that was used to - * populate the object. This acts as an object cache. - * @param TActiveRecord new clean object. - */ - public function registerClean($obj) - { - $this->removeCleanOrDirty($obj); - if($this->isRemovedObject($obj)) - throw new TActiveRecordException('ar_object_marked_for_removal'); - $this->_cleanObjects[] = array($obj, clone($obj)); - } - - /** - * Remove the object from dirty state. - * @param TActiveRecord object to remove. - */ - protected function removeDirty($obj) - { - $this->assertNotNull($obj); - foreach($this->_cleanObjects as $i=>$cache) - if($cache[0]===$obj && $obj != $cache[1]) - unset($this->_cleanObjects[$i]); - } - - /** - * Remove object from clean state. - * @param TActiveRecord object to remove. - */ - protected function removeClean($obj) - { - $this->assertNotNull($obj); - foreach($this->_cleanObjects as $i=>$cache) - if($cache[0]===$obj && $obj == $cache[1]) - unset($this->_cleanObjects[$i]); - } - - /** - * Remove object from dirty and clean state. - * @param TActiveRecord object to remove. - */ - protected function removeCleanOrDirty($obj) - { - $this->assertNotNull($obj); - foreach($this->_cleanObjects as $i=>$cache) - if($cache[0]===$obj) - unset($this->_cleanObjects[$i]); - } - - /** - * Remove object from removed state. - * @param TActiveRecord object to remove. - */ - protected function removeRemovedObject($obj) - { - $this->_removedObjects->remove($obj); - } - - /** - * Test whether an object is dirty or has been modified. - * @param TActiveRecord object to test. - * @return boolean true if the object is dirty, false otherwise. - */ - public function isDirtyObject($obj) - { - foreach($this->_cleanObjects as $cache) - if($cache[0] === $obj) - return $obj != $cache[1]; - return false; - } - - /** - * Test whether an object is in the clean state. - * @param TActiveRecord object to test. - * @return boolean true if object is clean, false otherwise. - */ - public function isCleanObject($obj) - { - foreach($this->_cleanObjects as $cache) - if($cache[0] === $obj) - return $obj == $cache[1]; - return false; - } - - /** - * Test whether an object is a new instance. - * @param TActiveRecord object to test. - * @return boolean true if object is newly created, false otherwise. - */ - public function isNewObject($obj) - { - if($this->isRemovedObject($obj)) return false; - foreach($this->_cleanObjects as $cache) - if($cache[0] === $obj) - return false; - return true; - } - - /** - * @param TActiveRecord object to test. - * @return boolean true if object is dirty or is new. - */ - public function shouldPersistObject($obj) - { - return $this->isDirtyObject($obj) || $this->isNewObject($obj); - } - - /** - * Test whether an object is marked for deletion. - * @param TActiveRecord object to test. - * @return boolean true if object is marked for deletion, false otherwise. - */ - public function isRemovedObject($obj) - { - return $this->_removedObjects->contains($obj); - } - - /** - * Commit the object to database: - * * a new record is inserted if the object is new, object becomes clean. - * * the record is updated if the object is dirty, object becomes clean. - * * the record is deleted if the object is marked for removal. - * - * @param TActiveRecord record object. - * @param TActiveRecordGateway database gateway - * @return boolean true if commit was successful, false otherwise. - */ - public function commit($record,$gateway) - { - $rowsAffected=false; - - if($this->isRemovedObject($record)) - { - $rowsAffected = $gateway->delete($record); - if($rowsAffected) - $this->removeRemovedObject($record); - } - else - { - if($this->isDirtyObject($record)) - $rowsAffected = $gateway->update($record); - else if($this->isNewObject($record)) - $rowsAffected = $gateway->insert($record); - - if($rowsAffected) - $this->registerClean($record); - } - return (boolean)$rowsAffected; - } -} - -?> \ No newline at end of file diff --git a/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js b/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js index 8f480d3d..87b8ddde 100644 --- a/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js +++ b/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js @@ -283,7 +283,7 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( } } }, - + setReadOnly : function(id, value) { var textbox = Prado.WebUI.TInPlaceTextBox.textboxes[id]; @@ -291,5 +291,5 @@ Prado.WebUI.TInPlaceTextBox = Base.extend( { textbox.readOnly=value; } - }, + } }); \ No newline at end of file diff --git a/tests/simple_unit/ActiveRecord/ForeignKeyTestCase.php b/tests/simple_unit/ActiveRecord/ForeignKeyTestCase.php index 2e4bee2d..d8017aeb 100644 --- a/tests/simple_unit/ActiveRecord/ForeignKeyTestCase.php +++ b/tests/simple_unit/ActiveRecord/ForeignKeyTestCase.php @@ -159,7 +159,6 @@ class ForeignKeyTestCase extends UnitTestCase function test_self_reference_fk() { $item = ItemRecord::finder()->withRelated_Items()->findByPk(1); - $this->assertNotNull($item); $this->assertEqual($item->name, "Professional Work Attire"); diff --git a/tests/simple_unit/ActiveRecord/MultipleForeignKeyTestCase.php b/tests/simple_unit/ActiveRecord/MultipleForeignKeyTestCase.php index 16036b9f..77408631 100644 --- a/tests/simple_unit/ActiveRecord/MultipleForeignKeyTestCase.php +++ b/tests/simple_unit/ActiveRecord/MultipleForeignKeyTestCase.php @@ -32,7 +32,7 @@ class Table1 extends MultipleFKSqliteRecord public $fk3; public $object1; - public $object2; + //public $object2; //commented out for testing __get/__set public $object3; public static $RELATIONS = array @@ -57,7 +57,7 @@ class Table2 extends MultipleFKSqliteRecord public $field1; private $_state1; - public $state2; + //public $state2; //commented out for testing __get/__set public $state3; public static $RELATIONS = array @@ -174,6 +174,19 @@ class MultipleForeignKeyTestCase extends UnitTestCase $this->assertEqual($obj->parent_category->cat_id, 1); } + + function testLazyLoadingGetterSetter_hasMany() + { + $arr = Table2::finder()->findByPk(2); + + $this->assertNotNull($arr->state2); //lazy load + $this->assertEqual(count($arr->state2), 1); + $this->assertEqual($arr->state2[0]->id, "1"); + $this->assertNotNull($arr->state2[0]->object2); + $this->assertEqual($arr->state2[0]->object2->id, "2"); + + $this->assertNotIdentical($arr, $arr->state2[0]->object2); + } } ?> \ No newline at end of file -- cgit v1.2.3