Skip to content
This repository
Browse code

FIXED: Issue where temporary table would cause unpredictable behaviou…

…r. Temporary table functionality was substituted with subqueries in each use case.

ADDED: Test case for version archive functionality.
  • Loading branch information...
commit 0f09305e3d31a98e41cfb9158dda14ba584931db 1 parent c55b018
Damian Mooyman authored August 20, 2012
59  model/Versioned.php
@@ -160,10 +160,19 @@ function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) {
160 160
 			}
161 161
 
162 162
 			// Link to the version archived on that date
163  
-			$archiveTable = $this->requireArchiveTempTable($baseTable, $date);
164  
-			$query->addFrom(array($archiveTable => "INNER JOIN \"$archiveTable\"
165  
-				ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" 
166  
-				AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\""));
  163
+			$safeDate = Convert::raw2sql($date);
  164
+			$query->addWhere(
  165
+					"`{$baseTable}_versions`.`Version` IN 
  166
+					(SELECT LatestVersion FROM 
  167
+						(SELECT 
  168
+							`{$baseTable}_versions`.`RecordID`, 
  169
+							MAX(`{$baseTable}_versions`.`Version`) AS LatestVersion
  170
+							FROM `{$baseTable}_versions`
  171
+							WHERE `{$baseTable}_versions`.`LastEdited` <= '$safeDate'
  172
+							GROUP BY `{$baseTable}_versions`.`RecordID`
  173
+						) AS `{$baseTable}_versions_latest`
  174
+						WHERE `{$baseTable}_versions_latest`.`RecordID` = `{$baseTable}_versions`.`RecordID`
  175
+					)");
167 176
 			break;
168 177
 		
169 178
 		// Reading a specific stage (Stage or Live)
@@ -204,10 +213,18 @@ function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) {
204 213
 			// Return latest version instances, regardless of whether they are on a particular stage
205 214
 			// This provides "show all, including deleted" functonality
206 215
 			if($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
207  
-				$archiveTable = self::requireArchiveTempTable($baseTable);
208  
-				$query->addInnerJoin($archiveTable, "\"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
  216
+				$query->addWhere(
  217
+					"`{$alias}_versions`.`Version` IN 
  218
+					(SELECT LatestVersion FROM 
  219
+						(SELECT 
  220
+							`{$alias}_versions`.`RecordID`, 
  221
+							MAX(`{$alias}_versions`.`Version`) AS LatestVersion
  222
+							FROM `{$alias}_versions`
  223
+							GROUP BY `{$alias}_versions`.`RecordID`
  224
+						) AS `{$alias}_versions_latest`
  225
+						WHERE `{$alias}_versions_latest`.`RecordID` = `{$alias}_versions`.`RecordID`
  226
+					)");
209 227
 			}
210  
-
211 228
 			break;
212 229
 		default:
213 230
 			throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
@@ -234,34 +251,6 @@ public static function on_db_reset() {
234 251
 		// Remove references to them
235 252
 		self::$archive_tables = array();
236 253
 	}
237  
-	
238  
-	/**
239  
-	 * Create a temporary table mapping each database record to its version on the given date.
240  
-	 * This is used by the versioning system to return database content on that date.
241  
-	 * @param string $baseTable The base table.
242  
-	 * @param string $date The date.  If omitted, then the latest version of each page will be returned.
243  
-	 * @todo Ensure that this is DB abstracted
244  
-	 */
245  
-	protected static function requireArchiveTempTable($baseTable, $date = null) {
246  
-		if(!isset(self::$archive_tables[$baseTable])) {
247  
-			self::$archive_tables[$baseTable] = DB::createTable("_Archive$baseTable", array(
248  
-				"ID" => "INT NOT NULL",
249  
-				"Version" => "INT NOT NULL",
250  
-			), null, array('temporary' => true));
251  
-		}
252  
-		
253  
-		if(!DB::query("SELECT COUNT(*) FROM \"" . self::$archive_tables[$baseTable] . "\"")->value()) {
254  
-			if($date) $dateClause = "WHERE \"LastEdited\" <= '$date'";
255  
-			else $dateClause = "";
256  
-
257  
-			DB::query("INSERT INTO \"" . self::$archive_tables[$baseTable] . "\"
258  
-				SELECT \"RecordID\", max(\"Version\") FROM \"{$baseTable}_versions\"
259  
-				$dateClause
260  
-				GROUP BY \"RecordID\"");
261  
-		}
262  
-		
263  
-		return self::$archive_tables[$baseTable];
264  
-	}
265 254
 
266 255
 	/**
267 256
 	 * An array of DataObject extensions that may require versioning for extra tables
53  tests/model/VersionedTest.php
@@ -266,6 +266,59 @@ public function testGetVersionWhenClassnameChanged() {
266 266
 		$this->assertInstanceOf("VersionedTest_DataObject", $obj3);
267 267
 
268 268
 	}
  269
+	
  270
+	public function testArchiveVersion() {
  271
+		
  272
+		// In 2005 this file was created
  273
+		SS_Datetime::set_mock_now('2005-01-01 00:00:00');
  274
+		$testPage = new VersionedTest_Subclass();
  275
+		$testPage->Title = 'Archived page';
  276
+		$testPage->Content = 'This is the content from 2005';
  277
+		$testPage->ExtraField = '2005';
  278
+		$testPage->write();
  279
+		$testPage->publish('Stage', 'Live');
  280
+		
  281
+		// In 2007 we updated it
  282
+		SS_Datetime::set_mock_now('2007-01-01 00:00:00');
  283
+		$testPage->Content = "It's 2007 already!";
  284
+		$testPage->ExtraField = '2007';
  285
+		$testPage->write();
  286
+		$testPage->publish('Stage', 'Live');
  287
+		
  288
+		// In 2009 we updated it again
  289
+		SS_Datetime::set_mock_now('2009-01-01 00:00:00');
  290
+		$testPage->Content = "I'm enjoying 2009";
  291
+		$testPage->ExtraField = '2009';
  292
+		$testPage->write();
  293
+		$testPage->publish('Stage', 'Live');
  294
+		
  295
+		// End mock, back to the present day:)
  296
+		SS_Datetime::clear_mock_now();
  297
+		
  298
+		// Test 1 - 2006 Content
  299
+		singleton('VersionedTest_Subclass')->flushCache(true);
  300
+		Versioned::set_reading_mode('Archive.2006-01-01 00:00:00');
  301
+		$testPage2006 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
  302
+		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2006);
  303
+		$this->assertEquals("2005", $testPage2006->ExtraField);
  304
+		$this->assertEquals("This is the content from 2005", $testPage2006->Content);
  305
+		
  306
+		// Test 2 - 2008 Content
  307
+		singleton('VersionedTest_Subclass')->flushCache(true);
  308
+		Versioned::set_reading_mode('Archive.2008-01-01 00:00:00');
  309
+		$testPage2008 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
  310
+		$this->assertInstanceOf("VersionedTest_Subclass", $testPage2008);
  311
+		$this->assertEquals("2007", $testPage2008->ExtraField);
  312
+		$this->assertEquals("It's 2007 already!", $testPage2008->Content);
  313
+		
  314
+		// Test 3 - Today
  315
+		singleton('VersionedTest_Subclass')->flushCache(true);
  316
+		Versioned::set_reading_mode('Stage.Stage');
  317
+		$testPageCurrent = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first();
  318
+		$this->assertInstanceOf("VersionedTest_Subclass", $testPageCurrent);
  319
+		$this->assertEquals("2009", $testPageCurrent->ExtraField);
  320
+		$this->assertEquals("I'm enjoying 2009", $testPageCurrent->Content);
  321
+	}
269 322
 }
270 323
 
271 324
 class VersionedTest_DataObject extends DataObject implements TestOnly {

0 notes on commit 0f09305

Please sign in to comment.
Something went wrong with that request. Please try again.