From 69928631fe918d13d27fd802d414084129fd9f93 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Wed, 18 Jul 2012 16:25:37 +1200 Subject: [PATCH 1/2] BUG trac 7482, we werent unlazying composite fields right In getField we check if the field we are getting is currently lazy (unloaded), and load it if it is. This was only working for simple fields though - composite fields like Money werent working --- model/DataObject.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/model/DataObject.php b/model/DataObject.php index 3f10d6416..90fbe5bf6 100644 --- a/model/DataObject.php +++ b/model/DataObject.php @@ -1920,7 +1920,15 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity if(self::is_composite_field($this->class, $field)) { $helper = $this->castingHelper($field); $fieldObj = Object::create_from_string($helper, $field); - + + $compositeFields = $fieldObj->compositeDatabaseFields(); + foreach ($compositeFields as $compositeName => $compositeType) { + if(isset($this->record[$field.$compositeName.'_Lazy'])) { + $tableClass = $this->record[$field.$compositeName.'_Lazy']; + $this->loadLazyFields($tableClass); + } + } + // write value only if either the field value exists, // or a valid record has been loaded from the database $value = (isset($this->record[$field])) ? $this->record[$field] : null; @@ -2092,9 +2100,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity // If we've just lazy-loaded the column, then we need to populate the $original array by // called getField(). Too much overhead? Could this be done by a quicker method? Maybe only // on a call to getChanged()? - if (isset($this->record[$fieldName.'_Lazy'])) { - $this->getField($fieldName); - } + $this->getField($fieldName); $this->record[$fieldName] = $val; // Situation 2: Passing a literal or non-DBField object @@ -2120,9 +2126,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity // If we've just lazy-loaded the column, then we need to populate the $original array by // called getField(). Too much overhead? Could this be done by a quicker method? Maybe only // on a call to getChanged()? - if (isset($this->record[$fieldName.'_Lazy'])) { - $this->getField($fieldName); - } + $this->getField($fieldName); // Value is always saved back when strict check succeeds. $this->record[$fieldName] = $val; From e8cd675c94920f4508d64e93ae1bc9358a8e4b4c Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Wed, 18 Jul 2012 16:28:24 +1200 Subject: [PATCH 2/2] BUG trac 7482 couldnt publish composite fields to live When publishing to live, DataObject#forceChange is called, which wasnt correctly loading in fields that were lazy (unloaded) if those fields were from composite fields like Money. The end result is that any Money values would be forced to null on publish to live Also changes the API of the (internal, protected) loadLazyFields method so that not passing a class argument just unlazys all lazy fields regardless of source table --- model/DataObject.php | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/model/DataObject.php b/model/DataObject.php index 90fbe5bf6..01fac1146 100644 --- a/model/DataObject.php +++ b/model/DataObject.php @@ -679,13 +679,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity * @return array The data as a map. */ public function toMap() { - foreach ($this->record as $key => $value) { - if (strlen($key) > 5 && substr($key, -5) == '_Lazy') { - $this->loadLazyFields($value); - break; - } - } - + $this->loadLazyFields(); return $this->record; } @@ -847,13 +841,16 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity * if they are not already marked as changed. */ public function forceChange() { + // Ensure lazy fields loaded + $this->loadLazyFields(); + // $this->record might not contain the blank values so we loop on $this->inheritedDatabaseFields() as well $fieldNames = array_unique(array_merge(array_keys($this->record), array_keys($this->inheritedDatabaseFields()))); foreach($fieldNames as $fieldName) { if(!isset($this->changed[$fieldName])) $this->changed[$fieldName] = 1; // Populate the null values in record so that they actually get written - if(!$this->$fieldName) $this->record[$fieldName] = null; + if(!isset($this->record[$fieldName])) $this->record[$fieldName] = null; } // @todo Find better way to allow versioned to write a new version after forceChange @@ -1954,13 +1951,24 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity } /** - * Loads all the stub fields than an initial lazy load didn't load fully. + * Loads all the stub fields that an initial lazy load didn't load fully. * * @param tableClass Base table to load the values from. Others are joined as required. + * Not specifying a tableClass will load all lazy fields from all tables. */ protected function loadLazyFields($tableClass = null) { - // Smarter way to work out the tableClass? Should the functionality in toMap and getField be moved into here? - if (!$tableClass) $tableClass = $this->ClassName; + if (!$tableClass) { + $loaded = array(); + + foreach ($this->record as $key => $value) { + if (strlen($key) > 5 && substr($key, -5) == '_Lazy' && !array_key_exists($value, $loaded)) { + $this->loadLazyFields($value); + $loaded[$value] = $value; + } + } + + return; + } $dataQuery = new DataQuery($tableClass);