ENHANCEMENT: Improved Versioned to pass different query styles as DataQuery modes.

This commit is contained in:
Sam Minnee 2011-03-21 19:53:09 +13:00
parent 319d2f4952
commit c57378753d

View File

@ -111,13 +111,14 @@ class Versioned extends DataExtension {
* Amend freshly created DataQuery objects with versioned-specific information
*/
function augmentDataQueryCreation(SQLQuery &$query, DataQuery &$dataQuery) {
if($date = Versioned::$reading_archived_date) {
$parts = explode('.', Versioned::get_reading_mode());
if($parts[0] == 'Archive') {
$dataQuery->setQueryParam('Versioned.mode', 'archive');
$dataQuery->setQueryParam('Versioned.date', Versioned::$reading_archived_date);
$dataQuery->setQueryParam('Versioned.date', $parts[1]);
} else if(Versioned::$reading_stage && Versioned::$reading_stage != $this->defaultStage && array_search(Versioned::$reading_stage,$this->stages) !== false) {
} else if($parts[0] == 'Stage' && $parts[1] != $this->defaultStage && array_search($parts[1],$this->stages) !== false) {
$dataQuery->setQueryParam('Versioned.mode', 'stage');
$dataQuery->setQueryParam('Versioned.stage', Versioned::$reading_stage);
$dataQuery->setQueryParam('Versioned.stage', $parts[1]);
}
}
@ -127,14 +128,17 @@ class Versioned extends DataExtension {
* @todo Should this all go into VersionedDataQuery?
*/
function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery) {
$baseTable = ClassInfo::baseDataClass($dataQuery->dataClass());
switch($dataQuery->getQueryParam('Versioned.mode')) {
// Noop
case '':
break;
// Reading a specific data from the archive
case 'archive':
$date = $dataQuery->getQueryParam('Versioned.date');
foreach($query->from as $table => $dummy) {
if(!isset($baseTable)) {
$baseTable = $table;
}
$query->renameTable($table, $table . '_versions');
$query->replaceText("\"$table\".\"ID\"", "\"$table\".\"RecordID\"");
@ -172,6 +176,36 @@ class Versioned extends DataExtension {
}
}
break;
// Return all version instances
case 'all_versions':
case 'latest_versions':
foreach($query->from as $alias => $join) {
if($alias != $baseTable) {
$query->setJoinFilter($alias, "\"$alias\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$alias\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
}
$query->renameTable($alias, $alias . '_versions');
}
// Add all <basetable>_versions columns
foreach(self::$db_for_versions_table as $name => $type) {
$query->selectMore(sprintf('"%s_versions"."%s"', $baseTable, $name));
}
$query->selectMore(sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID'));
// latest_version has one more step
// Return latest version instances, regardless of whether they are on a particular stage
// This provides "show all, including deleted" functonality
if($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
$archiveTable = self::requireArchiveTempTable($baseTable);
$query->innerJoin($archiveTable, "\"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
}
break;
default:
throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
}
}
@ -803,17 +837,11 @@ class Versioned extends DataExtension {
* @param string $orderby A sort expression to be inserted into the ORDER BY clause.
* @return DataObject
*/
static function get_one_by_stage($class, $stage, $filter = '', $cache = true, $orderby = '') {
$oldMode = Versioned::get_reading_mode();
Versioned::reading_stage($stage);
singleton($class)->flushCache();
$result = DataObject::get_one($class, $filter, $cache, $orderby);
singleton($class)->flushCache();
Versioned::set_reading_mode($oldMode);
return $result;
}
static function get_one_by_stage($class, $stage, $filter = '', $cache = true, $sort = '') {
// TODO: No identity cache operating
$items = self::get_by_stage($class, $stage, $filter, $sort, null, 1);
return $items->First();
}
/**
* Gets the current version number of a specific record.
@ -832,7 +860,7 @@ class Versioned extends DataExtension {
if($cache && isset(self::$cache_versionnumber[$baseClass][$stage][$id])) {
return self::$cache_versionnumber[$baseClass][$stage][$id];
}
// get version as performance-optimized SQL query (gets called for each page in the sitetree)
$version = DB::query("SELECT \"Version\" FROM \"$stageTable\" WHERE \"ID\" = $id")->value();
@ -908,7 +936,7 @@ class Versioned extends DataExtension {
Versioned::set_reading_mode($oldMode);
return $result;
}
/**
* Roll the draft version of this page to match the published page.
* Caution: Doesn't overwrite the object properties with the rolled back version.
@ -919,44 +947,6 @@ class Versioned extends DataExtension {
$this->publish($version, "Stage", true);
$this->owner->writeWithoutVersion();
}
/**
* Build a SQL query to get data from the _version table.
* This function is similar in style to {@link DataObject::buildSQL}
*/
function buildVersionSQL($filter = "", $sort = "") {
$query = $this->owner->extendedSQL($filter,$sort);
foreach($query->from as $table => $join) {
if($join[0] == '"') $baseTable = str_replace('"','',$join);
else $query->from[$table] = "LEFT JOIN \"$table\" ON \"$table\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$table\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
$query->renameTable($table, $table . '_versions');
}
// Add all <basetable>_versions columns
foreach(self::$db_for_versions_table as $name => $type) {
$query->select[] = sprintf('"%s_versions"."%s"', $baseTable, $name);
}
$query->select[] = sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID');
return $query;
}
static function build_version_sql($className, $filter = "", $sort = "") {
$query = singleton($className)->extendedSQL($filter,$sort);
foreach($query->from as $table => $join) {
if($join[0] == '"') $baseTable = str_replace('"','',$join);
else $query->from[$table] = "LEFT JOIN \"$table\" ON \"$table\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$table\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
$query->renameTable($table, $table . '_versions');
}
// Add all <basetable>_versions columns
foreach(self::$db_for_versions_table as $name => $type) {
$query->select[] = sprintf('"%s_versions"."%s"', $baseTable, $name);
}
$query->select[] = sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID');
return $query;
}
/**
* Return the latest version of the given page.
@ -964,25 +954,10 @@ class Versioned extends DataExtension {
* @return DataObject
*/
static function get_latest_version($class, $id) {
$oldMode = Versioned::get_reading_mode();
Versioned::set_reading_mode('');
$baseTable = ClassInfo::baseDataClass($class);
$query = singleton($class)->buildVersionSQL("\"{$baseTable}\".\"RecordID\" = $id", "\"{$baseTable}\".\"Version\" DESC");
$query->limit = 1;
$record = $query->execute()->record();
if(!$record) return;
$className = $record['ClassName'];
if(!$className) {
Debug::show($query->sql());
Debug::show($record);
user_error("Versioned::get_version: Couldn't get $class.$id", E_USER_ERROR);
}
Versioned::set_reading_mode($oldMode);
return new $className($record);
$baseClass = ClassInfo::baseDataClass($class);
$list = DataList::create($class)->filter("\"$baseClass\".\"RecordID\" = $id");
$list->dataQuery()->setQueryParam("Versioned.mode", "latest_versions");
return $list->First();
}
/**
@ -992,61 +967,31 @@ class Versioned extends DataExtension {
* In particular, this will query deleted records as well as active ones.
*/
static function get_including_deleted($class, $filter = "", $sort = "") {
$oldMode = Versioned::get_reading_mode();
Versioned::set_reading_mode('');
$SNG = singleton($class);
// Build query
$query = $SNG->buildVersionSQL($filter, $sort);
$baseTable = ClassInfo::baseDataClass($class);
$archiveTable = self::requireArchiveTempTable($baseTable);
$query->from[$archiveTable] = "INNER JOIN \"$archiveTable\"
ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\"
AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
// Process into a DataObjectSet
$result = $SNG->buildDataObjectSet($query->execute(), 'DataObjectSet', null, $class);
Versioned::set_reading_mode($oldMode);
return $query;
$list = DataList::create($class)->filter($filter)->sort($sort);
$list->dataQuery()->setQueryParam("Versioned.mode", "latest_versions");
return $list;
}
/**
* Return the specific version of the given id
* @return DataObject
*/
static function get_version($class, $id, $version) {
$oldMode = Versioned::get_reading_mode();
Versioned::set_reading_mode('');
$baseTable = ClassInfo::baseDataClass($class);
$query = singleton($class)->buildVersionSQL("\"{$baseTable}\".\"RecordID\" = $id AND \"{$baseTable}\".\"Version\" = $version");
$record = $query->execute()->record();
$className = $record['ClassName'];
if(!$className) {
Debug::show($query->sql());
Debug::show($record);
user_error("Versioned::get_version: Couldn't get $class.$id, version $version", E_USER_ERROR);
}
Versioned::set_reading_mode($oldMode);
return new $className($record);
$baseClass = ClassInfo::baseDataClass($class);
$list = DataList::create($class)->filter("\"$baseClass\".\"RecordID\" = $id")->filter("\"$baseClass\".\"Version\" = " . (int)$version);
$list->dataQuery()->setQueryParam('Versioned.mode', 'all_versions');
return $list->First();
}
/**
* @return DataObject
* Return a list of all versions for a given id
* @return DataList
*/
static function get_all_versions($class, $id, $version) {
$baseTable = ClassInfo::baseDataClass($class);
$query = singleton($class)->buildVersionSQL("\"{$baseTable}\".\"RecordID\" = $id AND \"{$baseTable}\".\"Version\" = $version");
$record = $query->execute()->record();
$className = $record['ClassName'];
if(!$className) {
Debug::show($query->sql());
Debug::show($record);
user_error("Versioned::get_version: Couldn't get $class.$id, version $version", E_USER_ERROR);
}
return new $className($record);
static function get_all_versions($class, $id) {
$baseClass = ClassInfo::baseDataClass($class);
$list = DataList::create($class)->filter("\"$baseClass\".\"RecordID\" = $id");
$list->dataQuery()->setQueryParam('Versioned.mode', 'all_versions');
return $list;
}
function contentcontrollerInit($controller) {
@ -1070,7 +1015,7 @@ class Versioned extends DataExtension {
* Return a piece of text to keep DataObject cache keys appropriately specific
*/
function cacheKeyComponent() {
return 'stage-'.self::current_stage();
return 'versionedmode-'.self::get_reading_mode();
}
}