Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

BUG Fix DataObject / Versioned publishing issues #2917

Merged
merged 1 commit into from

3 participants

@tractorcow
Owner

This issue was initially raised at and fixes silverstripe/silverstripe-blog#105.

After investigation I found the following issues.

If a DataObject was queried under a certain stage or reading mode, and then this mode changes, lazy-loading of fields would fail since it will always attempt to use the current mode. This is fixed in DataObject::loadLazyFields so that any DataObject will maintain it's own query parameters internally, propegating this context from initial load all the way to lazy loading of fields.

This fix was made in DataObject rather than in Versioned::augmentLoadLazyFields because (in my humble opinion) it's the role of the DataObject to maintain its own query context, and it should only be touched by extensions to modify this explicitly. This is easier than updating each dataobject extension across the board.

Secondly, Versioned::writeToStage was failing if no fields were modified, meaning simply loading a record from one stage and writing it to another would result in no write performed.

Test cases were included in VersionedTest rather than DataObjectLazyLoadingTest becuase I feel that this is more a test of the Versioned extension (and DataObject's support for extensions) than the lazy loading process itself. I could just as easy have put it there though. :)

I've marked this as "don't merge" because I'd like to get a few developer opinions before I'm confident this is the correct solution.

@tractorcow tractorcow BUG Fix DataObject::loadLazyFields discarding original query parameters
BUG Fix Versioned::writeToStage failing to write object with unchanged fields
23f5f08
@tractorcow
Owner

@sunnysideup would you like to peer-review my PR? :)

@sunnysideup

Sure, what is the best way to do this? review the code or how it works or both etc...???

@tractorcow
Owner

I just wonder if my thinking is correct in the getSourceQueryParams part of the code; If a dataobject is queried, is it wise to do a blind restore of the original query parameters when lazy loading?

@tractorcow
Owner

Removed the "don't merge" - I think this can go into core as long as it's checked by another developer before they merge it.

@sunnysideup

I just had a first look. It seems to make sense.

what if Query Params are already set, will it double-up or have too many query params? I am not sure if that is even relevant, but just wanted to check. I dont think this is an issue - and I think you are basically wondering about the same thing. I just wonder how I can even test this.

because it such a CORE CORE change, would it be worthwhile to work out how much longer it takes to run the code to avoid it slowing down EVERYTHING? This would be fairly easy to test and it is important to know.

@tractorcow
Owner

Thanks for the review. :)

QueryParams are already set in the DataQuery constructor to the current defaults, such as versioned stage, etc. The code above simply overwrites any default keys with those saved on the DataObject, so it won't remove any keys. This might cause problems if any extension relies on the absence of any query param to work...

I don't think it's going to be a performance hit; It's just copying variables from one object into the DataQuery.

@simonwelsh

I saw an old issue that this fixes too. I guess I'll have to go find it now :p

@simonwelsh simonwelsh merged commit 90ba514 into silverstripe:3.1
@tractorcow tractorcow deleted the tractorcow:pulls/fix-lazyload-queryparams branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 4, 2014
  1. @tractorcow

    BUG Fix DataObject::loadLazyFields discarding original query parameters

    tractorcow authored
    BUG Fix Versioned::writeToStage failing to write object with unchanged fields
This page is out of date. Refresh to see the latest.
View
5 model/DataObject.php
@@ -2166,6 +2166,11 @@ protected function loadLazyFields($tableClass = null) {
}
$dataQuery = new DataQuery($tableClass);
+
+ // Reset query parameter context to that of this DataObject
+ if($params = $this->getSourceQueryParams()) {
+ foreach($params as $key => $value) $dataQuery->setQueryParam($key, $value);
+ }
// TableField sets the record ID to "new" on new row data, so don't try doing anything in that case
if(!is_numeric($this->record['ID'])) return false;
View
1  model/Versioned.php
@@ -1184,6 +1184,7 @@ public function writeToStage($stage, $forceInsert = false) {
$oldMode = Versioned::get_reading_mode();
Versioned::reading_stage($stage);
+ $this->owner->forceChange();
$result = $this->owner->write(false, $forceInsert);
Versioned::set_reading_mode($oldMode);
View
41 tests/model/VersionedTest.php
@@ -492,6 +492,47 @@ public function testVersionedWithSingleStage() {
'Writes to and reads from default stage even if a non-matching stage is set'
);
}
+
+ /**
+ * Test that publishing processes respects lazy loaded fields
+ */
+ public function testLazyLoadFields() {
+ $originalMode = Versioned::get_reading_mode();
+
+ // Generate staging record and retrieve it from stage in live mode
+ Versioned::reading_stage('Stage');
+ $obj = new VersionedTest_Subclass();
+ $obj->Name = 'bob';
+ $obj->ExtraField = 'Field Value';
+ $obj->write();
+ $objID = $obj->ID;
+ $filter = sprintf('"VersionedTest_DataObject"."ID" = \'%d\'', Convert::raw2sql($objID));
+ Versioned::reading_stage('Live');
+
+ // Check fields are unloaded prior to access
+ $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
+ $lazyFields = $objLazy->getQueriedDatabaseFields();
+ $this->assertTrue(isset($lazyFields['ExtraField_Lazy']));
+ $this->assertEquals('VersionedTest_Subclass', $lazyFields['ExtraField_Lazy']);
+
+ // Check lazy loading works when viewing a Stage object in Live mode
+ $this->assertEquals('Field Value', $objLazy->ExtraField);
+
+ // Test that writeToStage respects lazy loaded fields
+ $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
+ $objLazy->writeToStage('Live');
+ $objLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', $filter, false);
+ $liveLazyFields = $objLive->getQueriedDatabaseFields();
+
+ // Check fields are unloaded prior to access
+ $this->assertTrue(isset($liveLazyFields['ExtraField_Lazy']));
+ $this->assertEquals('VersionedTest_Subclass', $liveLazyFields['ExtraField_Lazy']);
+
+ // Check that live record has original value
+ $this->assertEquals('Field Value', $objLive->ExtraField);
+
+ Versioned::set_reading_mode($originalMode);
+ }
}
Something went wrong with that request. Please try again.