Skip to content

Commit

Permalink
NEW Add new methods for querying data in various version modes
Browse files Browse the repository at this point in the history
Needed to convert existing CMSSiteTreeFilter implementations from using
filterByCallback() to instead perform all filtering inside the database.
  • Loading branch information
GuySartorelli committed Jan 30, 2025
1 parent ee61bd5 commit 4052391
Showing 1 changed file with 128 additions and 17 deletions.
145 changes: 128 additions & 17 deletions src/Versioned.php
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ protected function augmentSQL(SQLSelect $query, ?DataQuery $dataQuery = null)
case 'archive':
$this->augmentSQLVersionedArchive($query, $dataQuery);
break;
case 'archive_only':
$this->augmentSQLVersionedArchiveOnly($query, $dataQuery);
break;
case 'removed_on_draft':
$this->augmentSQLVersionedRemovedOnDraft($query, $dataQuery);
break;
case 'latest_version_single':
$this->augmentSQLVersionedLatestSingle($query, $dataQuery);
break;
Expand Down Expand Up @@ -744,6 +750,36 @@ protected function augmentSQLVersionedArchive(SQLSelect $query, DataQuery $dataQ
);
}

protected function augmentSQLVersionedArchiveOnly(SQLSelect $query, DataQuery $dataQuery): void
{
$baseTable = $this->baseTable();
$liveTable = $this->stageTable($baseTable, Versioned::LIVE);

$query->addLeftJoin(
$liveTable,
"\"{$baseTable}\".\"ID\" = \"{$liveTable}\".\"ID\""
);
$query->addWhere("\"{$liveTable}\".\"ID\" IS NULL");

$this->augmentSQLVersionedRemovedOnDraft($query, $dataQuery);
}

protected function augmentSQLVersionedRemovedOnDraft(SQLSelect $query, DataQuery $dataQuery): void
{
$baseTable = $this->baseTable();

// Join a temporary alias BaseTable_Draft, renaming this on execution to BaseTable
// See Versioned::augmentSQLVersioned() For reference on this alias
$query->addLeftJoin(
"{$baseTable}_Draft",
"\"{$baseTable}\".\"ID\" = \"{$baseTable}_Draft\".\"ID\""
);

$query->addWhere("\"{$baseTable}_Draft\".\"ID\" IS NULL");

$this->augmentSQLVersionedLatest($query, $dataQuery);
}

/**
* Return latest version instance, regardless of whether it is on a particular stage.
* This is similar to augmentSQLVersionedLatest() below, except it only returns a single value
Expand Down Expand Up @@ -2479,24 +2515,29 @@ public static function prepopulate_versionnumber_cache($class, $stage, $idList =
* @template T of DataObject
* @param class-string<T> $class The name of the class.
* @param string $stage The name of the stage.
* @param string $filter A filter to be inserted into the WHERE clause.
* @param string $sort A sort expression to be inserted into the ORDER BY clause.
* @param int $limit A limit on the number of records returned from the database.
* @param string $containerClass The container class for the result set (default is DataList)
*
* @return DataList<T> A modified DataList designated to the specified stage
*/
public static function get_by_stage(
$class,
$stage,
$filter = '',
$sort = '',
$limit = null,
$containerClass = DataList::class
) {
ReadingMode::validateStage($stage);
string $class,
string $stage,
string|array $filter = '',
string|array|null $sort = '',
string|array|null $limit = null,
string $containerClass = DataList::class
): DataList {
$result = DataObject::get($class, $filter, $sort, $limit, $containerClass);
return $result->setDataQueryParam([
return static::updateListForStage($result, $stage);
}

/**
* Update an existing DataList to only include records for a given stage.
*/
public static function updateListForStage(DataList $list, string $stage): DataList
{
ReadingMode::validateStage($stage);
return $list->setDataQueryParam([
'Versioned.mode' => 'stage',
'Versioned.stage' => $stage
]);
Expand Down Expand Up @@ -2784,11 +2825,11 @@ public function isModifiedOnDraft()
*
* @template T of DataObject
* @param class-string<T> $class
* @param string $filter
* @param string $sort
* @param string $filter Explicitly used in where clause as raw SQL - use with caution!
* @param string $sort Explicitly used in orderBy clause as raw SQL - use with caution!
* @return DataList<T>
*/
public static function get_including_deleted($class, $filter = "", $sort = "")
public static function get_including_deleted(string $class, string|array $filter = '', string $sort = ''): DataList
{
$list = DataList::create($class);
if (!empty($filter)) {
Expand All @@ -2797,8 +2838,78 @@ public static function get_including_deleted($class, $filter = "", $sort = "")
if (!empty($sort)) {
$list = $list->orderBy($sort);
}
$list = $list->setDataQueryParam("Versioned.mode", "latest_versions");
return $list;
return static::updateListToIncludeDeleted($list);
}

/**
* Update a DataList to query the latest version of each record stored in the (class)_Versions tables.
*
* In particular, this will query deleted records as well as active ones.
*/
public static function updateListToIncludeDeleted(DataList $list): DataList
{
return $list->setDataQueryParam('Versioned.mode', 'latest_versions');
}

/**
* Return the equivalent of a DataList::create() call, querying only records which have been removed
* from draft. This includes archived records and records which were published but have no draft record.
*
* @template T of DataObject
* @param class-string<T> $class
* @param string $where Explicitly used in where clause as raw SQL - use with caution!
* @param string $orderBy Explicitly used in orderBy clause as raw SQL - use with caution!
* @return DataList<T>
*/
public static function getRemovedOnDraft(string $class, string|array $where = '', string $orderBy = ''): DataList
{
$list = DataList::create($class);
if (!empty($where)) {
$list = $list->where($where);
}
if (!empty($orderBy)) {
$list = $list->orderBy($orderBy);
}
return static::updateListToIncludeRemovedOnDraft($list);
}

/**
* Update a DataList to query only records which have been removed from draft.
* This includes archived records and records which were published but have no draft record.
*/
public static function updateListToIncludeRemovedOnDraft(DataList $list): DataList
{
return $list->setDataQueryParam('Versioned.mode', 'removed_on_draft');
}

/**
* Return the equivalent of a DataList::create() call, querying only records which are archived
* (i.e. removed in both draft and live)
*
* @template T of DataObject
* @param class-string<T> $class
* @param string $where Explicitly used in where clause as raw SQL - use with caution!
* @param string $orderBy Explicitly used in orderBy clause as raw SQL - use with caution!
* @return DataList<T>
*/
public static function getArchivedOnly(string $class, string|array $where = '', string $orderBy = ''): DataList
{
$list = DataList::create($class);
if (!empty($where)) {
$list = $list->where($where);
}
if (!empty($orderBy)) {
$list = $list->orderBy($orderBy);
}
return static::updateListToIncludeArchivedOnly($list);
}

/**
* Update a DataList to query only records which are archived (i.e. removed in both draft and live)
*/
public static function updateListToIncludeArchivedOnly(DataList $list): DataList
{
return $list->setDataQueryParam('Versioned.mode', 'archive_only');
}

/**
Expand Down

0 comments on commit 4052391

Please sign in to comment.