mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API CHANGE: Add SQLQuery::clearSelect(), SQLQuery::selectField() and SQLQuery::itemisedSelect() to make it easier for other subsystems to use SQLQuery without resorting to direct property access.
API CHANGE: Remove DataQuery::select() in place of DataQuery::selectField(). BUGFIX: Remove direct property access to SQLQuery::$select
This commit is contained in:
parent
3cd4b33121
commit
8661164c19
@ -77,7 +77,7 @@ class ManyManyComplexTableField extends HasManyComplexTableField {
|
|||||||
|
|
||||||
function getQuery() {
|
function getQuery() {
|
||||||
$query = parent::getQuery();
|
$query = parent::getQuery();
|
||||||
$query->select[] = "CASE WHEN \"{$this->manyManyParentClass}ID\" IS NULL THEN '0' ELSE '1' END AS \"Checked\"";
|
$query->selectField("CASE WHEN \"{$this->manyManyParentClass}ID\" IS NULL THEN '0' ELSE '1' END", "Checked");
|
||||||
$query->groupby[] = "\"{$this->manyManyParentClass}ID\""; // necessary for Postgres
|
$query->groupby[] = "\"{$this->manyManyParentClass}ID\""; // necessary for Postgres
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
|
@ -78,7 +78,7 @@ class Aggregate extends ViewableData {
|
|||||||
protected function query($attr) {
|
protected function query($attr) {
|
||||||
$singleton = singleton($this->type);
|
$singleton = singleton($this->type);
|
||||||
$query = $singleton->buildSQL($this->filter);
|
$query = $singleton->buildSQL($this->filter);
|
||||||
$query->select = array($attr);
|
$query->select($attr);
|
||||||
$query->orderby = null;
|
$query->orderby = null;
|
||||||
$singleton->extend('augmentSQL', $query);
|
$singleton->extend('augmentSQL', $query);
|
||||||
return $query;
|
return $query;
|
||||||
@ -161,7 +161,7 @@ class Aggregate_Relationship extends Aggregate {
|
|||||||
$query = $this->object->getManyManyComponentsQuery($this->relationship, $this->filter);
|
$query = $this->object->getManyManyComponentsQuery($this->relationship, $this->filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->select = array($attr);
|
$query->select($attr);
|
||||||
$query->groupby = array();
|
$query->groupby = array();
|
||||||
|
|
||||||
$singleton = singleton($this->type);
|
$singleton = singleton($this->type);
|
||||||
|
@ -205,8 +205,7 @@ class DataQuery {
|
|||||||
user_error("Bad collision item '$collision'", E_USER_WARNING);
|
user_error("Bad collision item '$collision'", E_USER_WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$query->select[$k] = "CASE " . implode( " ", $caseClauses) . " ELSE NULL END"
|
$query->selectField("CASE " . implode( " ", $caseClauses) . " ELSE NULL END", $k);
|
||||||
. " AS \"$k\"";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,8 +220,8 @@ class DataQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->select[] = "\"$baseClass\".\"ID\"";
|
$query->selectField("\"$baseClass\".\"ID\"", "ID");
|
||||||
$query->select[] = "CASE WHEN \"$baseClass\".\"ClassName\" IS NOT NULL THEN \"$baseClass\".\"ClassName\" ELSE '$baseClass' END AS \"RecordClassName\"";
|
$query->selectField("CASE WHEN \"$baseClass\".\"ClassName\" IS NOT NULL THEN \"$baseClass\".\"ClassName\" ELSE '$baseClass' END", "RecordClassName");
|
||||||
|
|
||||||
// TODO: Versioned, Translatable, SiteTreeSubsites, etc, could probably be better implemented as subclasses of DataQuery
|
// TODO: Versioned, Translatable, SiteTreeSubsites, etc, could probably be better implemented as subclasses of DataQuery
|
||||||
singleton($this->dataClass)->extend('augmentSQL', $query, $this);
|
singleton($this->dataClass)->extend('augmentSQL', $query, $this);
|
||||||
@ -274,14 +273,18 @@ class DataQuery {
|
|||||||
$qualCol = "\"$parts[0]\"";
|
$qualCol = "\"$parts[0]\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
|
||||||
|
// format internally; then this check can be part of selectField()
|
||||||
if(!isset($query->select[$col]) && !in_array($qualCol, $query->select)) {
|
if(!isset($query->select[$col]) && !in_array($qualCol, $query->select)) {
|
||||||
$query->select[] = $qualCol;
|
$query->selectField($qualCol);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$qualCol = '"' . implode('"."', $parts) . '"';
|
$qualCol = '"' . implode('"."', $parts) . '"';
|
||||||
|
|
||||||
|
// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
|
||||||
|
// format internally; then this check can be part of selectField()
|
||||||
if(!in_array($qualCol, $query->select)) {
|
if(!in_array($qualCol, $query->select)) {
|
||||||
$query->select[] = $qualCol;
|
$query->selectField($qualCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,12 +370,12 @@ class DataQuery {
|
|||||||
if($databaseFields) foreach($databaseFields as $k => $v) {
|
if($databaseFields) foreach($databaseFields as $k => $v) {
|
||||||
if((is_null($columns) || in_array($k, $columns)) && !isset($compositeFields[$k])) {
|
if((is_null($columns) || in_array($k, $columns)) && !isset($compositeFields[$k])) {
|
||||||
// Update $collidingFields if necessary
|
// Update $collidingFields if necessary
|
||||||
if(isset($query->select[$k])) {
|
if($expressionForField = $query->expressionForField($k)) {
|
||||||
if(!isset($this->collidingFields[$k])) $this->collidingFields[$k] = array($query->select[$k]);
|
if(!isset($this->collidingFields[$k])) $this->collidingFields[$k] = array($expressionForField);
|
||||||
$this->collidingFields[$k][] = "\"$tableClass\".\"$k\"";
|
$this->collidingFields[$k][] = "\"$tableClass\".\"$k\"";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$query->select[$k] = "\"$tableClass\".\"$k\"";
|
$query->selectField("\"$tableClass\".\"$k\"", $k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,8 +599,12 @@ class DataQuery {
|
|||||||
*/
|
*/
|
||||||
public function subtract(DataQuery $subtractQuery, $field='ID') {
|
public function subtract(DataQuery $subtractQuery, $field='ID') {
|
||||||
$subSelect= $subtractQuery->getFinalisedQuery();
|
$subSelect= $subtractQuery->getFinalisedQuery();
|
||||||
$subSelect->select($this->expressionForField($field, $subSelect));
|
$fieldExpression = $this->expressionForField($field, $subSelect);
|
||||||
|
$subSelect->clearSelect();
|
||||||
|
$subSelect->selectField($fieldExpression);
|
||||||
$this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')');
|
$this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')');
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -607,7 +614,9 @@ class DataQuery {
|
|||||||
$fieldExpressions = array_map(create_function('$item',
|
$fieldExpressions = array_map(create_function('$item',
|
||||||
"return '\"$table\".\"' . \$item . '\"';"), $fields);
|
"return '\"$table\".\"' . \$item . '\"';"), $fields);
|
||||||
|
|
||||||
$this->select($fieldExpressions);
|
$this->query->select($fieldExpressions);
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -636,7 +645,7 @@ class DataQuery {
|
|||||||
* Clear the selected fields to start over
|
* Clear the selected fields to start over
|
||||||
*/
|
*/
|
||||||
public function clearSelect() {
|
public function clearSelect() {
|
||||||
$this->query->select = array();
|
$this->query->clearSelect();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -644,8 +653,8 @@ class DataQuery {
|
|||||||
/**
|
/**
|
||||||
* Select the given field expressions. You must do your own escaping
|
* Select the given field expressions. You must do your own escaping
|
||||||
*/
|
*/
|
||||||
protected function select($fieldExpressions) {
|
protected function selectField($fieldExpression, $alias = null) {
|
||||||
$this->query->select = array_merge($this->query->select, $fieldExpressions);
|
$this->query->selectField($fieldExpression, $alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
//// QUERY PARAMS
|
//// QUERY PARAMS
|
||||||
|
@ -133,7 +133,7 @@ class ManyManyList extends RelationList {
|
|||||||
function removeAll() {
|
function removeAll() {
|
||||||
$query = $this->dataQuery()->query();
|
$query = $this->dataQuery()->query();
|
||||||
$query->delete = true;
|
$query->delete = true;
|
||||||
$query->select = array('*');
|
$query->select(array('*'));
|
||||||
$query->from = array("\"$this->joinTable\"");
|
$query->from = array("\"$this->joinTable\"");
|
||||||
$query->orderby = null;
|
$query->orderby = null;
|
||||||
$query->execute();
|
$query->execute();
|
||||||
|
@ -113,6 +113,14 @@ class SQLQuery {
|
|||||||
$this->limit($limit);
|
$this->limit($limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the selected fields to start over
|
||||||
|
*/
|
||||||
|
function clearSelect() {
|
||||||
|
$this->select = array();
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the list of columns to be selected by the query.
|
* Specify the list of columns to be selected by the query.
|
||||||
*
|
*
|
||||||
@ -153,9 +161,26 @@ class SQLQuery {
|
|||||||
$this->select[] = $fields;
|
$this->select[] = $fields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select an additional field
|
||||||
|
*
|
||||||
|
* @param $field The field to select
|
||||||
|
* @param $alias The alias of that field
|
||||||
|
*/
|
||||||
|
public function selectField($field, $alias = null) {
|
||||||
|
// Let's not put unnecessary aliases into the query
|
||||||
|
if($alias && preg_match('/"' . preg_quote($alias) . '"$/', $field)) {
|
||||||
|
$alias = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($alias) $this->select[] = "$field AS \"$alias\"";
|
||||||
|
else $this->select[] = $field;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the SQL expression for the given field
|
* Return the SQL expression for the given field alias.
|
||||||
|
* Returns null if the given alias doesn't exist.
|
||||||
*
|
*
|
||||||
* @todo This should be refactored after $this->select is changed to make that easier
|
* @todo This should be refactored after $this->select is changed to make that easier
|
||||||
*/
|
*/
|
||||||
@ -166,6 +191,7 @@ class SQLQuery {
|
|||||||
else if(preg_match('/"?([^"]*)"?/', $sel, $matches)) $selField = $matches[2];
|
else if(preg_match('/"?([^"]*)"?/', $sel, $matches)) $selField = $matches[2];
|
||||||
if($selField == $field) return $sel;
|
if($selField == $field) return $sel;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -542,6 +568,29 @@ class SQLQuery {
|
|||||||
Deprecation::notice('3.0', 'Please use prepareWhere() instead of getFilter()');
|
Deprecation::notice('3.0', 'Please use prepareWhere() instead of getFilter()');
|
||||||
return $this->prepareWhere();
|
return $this->prepareWhere();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an itemised select list as a map, where keys are the aliases, and values are the column sources.
|
||||||
|
* Aliases will always be provided (if the alias is implicit, the alias value will be inferred), and won't be quoted.
|
||||||
|
* E.g., 'Title' => '"SiteTree"."Title"'.
|
||||||
|
*/
|
||||||
|
public function itemisedSelect() {
|
||||||
|
$output = array();
|
||||||
|
foreach($this->select as $item) {
|
||||||
|
$split = preg_split('/ AS /i', $item, 2);
|
||||||
|
if(isset($split[1])) {
|
||||||
|
$source = $split[0];
|
||||||
|
$alias = $split[1];
|
||||||
|
} else {
|
||||||
|
$source = $item;
|
||||||
|
$alias = substr($item,strrpos($item,'.')+1);
|
||||||
|
}
|
||||||
|
// Drop quoting
|
||||||
|
$alias = preg_replace('/^"(.*)"$/','\\1', $alias);
|
||||||
|
$output[$alias] = $source;
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the WHERE clauses ready for inserting into a query.
|
* Returns the WHERE clauses ready for inserting into a query.
|
||||||
|
@ -149,9 +149,9 @@ class Versioned extends DataExtension {
|
|||||||
|
|
||||||
// Add all <basetable>_versions columns
|
// Add all <basetable>_versions columns
|
||||||
foreach(self::$db_for_versions_table as $name => $type) {
|
foreach(self::$db_for_versions_table as $name => $type) {
|
||||||
$query->select[] = sprintf('"%s_versions"."%s"', $baseTable, $name);
|
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
|
||||||
}
|
}
|
||||||
$query->select[] = sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID');
|
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
|
||||||
|
|
||||||
if($table != $baseTable) {
|
if($table != $baseTable) {
|
||||||
$query->from[$table] .= " AND \"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
|
$query->from[$table] .= " AND \"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
|
||||||
@ -195,9 +195,9 @@ class Versioned extends DataExtension {
|
|||||||
|
|
||||||
// Add all <basetable>_versions columns
|
// Add all <basetable>_versions columns
|
||||||
foreach(self::$db_for_versions_table as $name => $type) {
|
foreach(self::$db_for_versions_table as $name => $type) {
|
||||||
$query->selectMore(sprintf('"%s_versions"."%s"', $baseTable, $name));
|
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
|
||||||
}
|
}
|
||||||
$query->selectMore(sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID'));
|
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
|
||||||
|
|
||||||
// latest_version has one more step
|
// latest_version has one more step
|
||||||
// Return latest version instances, regardless of whether they are on a particular stage
|
// Return latest version instances, regardless of whether they are on a particular stage
|
||||||
@ -722,7 +722,7 @@ class Versioned extends DataExtension {
|
|||||||
|
|
||||||
// Add all <basetable>_versions columns
|
// Add all <basetable>_versions columns
|
||||||
foreach(self::$db_for_versions_table as $name => $type) {
|
foreach(self::$db_for_versions_table as $name => $type) {
|
||||||
$query->select[] = sprintf('"%s_versions"."%s"', $baseTable, $name);
|
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->where[] = "\"{$baseTable}_versions\".\"RecordID\" = '{$this->owner->ID}'";
|
$query->where[] = "\"{$baseTable}_versions\".\"RecordID\" = '{$this->owner->ID}'";
|
||||||
|
@ -96,8 +96,8 @@ class Money extends DBField implements CompositeDBField {
|
|||||||
|
|
||||||
function addToQuery(&$query) {
|
function addToQuery(&$query) {
|
||||||
parent::addToQuery($query);
|
parent::addToQuery($query);
|
||||||
$query->select[] = sprintf('"%sAmount"', $this->name);
|
$query->selectField(sprintf('"%sAmount"', $this->name));
|
||||||
$query->select[] = sprintf('"%sCurrency"', $this->name);
|
$query->selectField(sprintf('"%sCurrency"', $this->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setValue($value, $record = null, $markChanged = true) {
|
function setValue($value, $record = null, $markChanged = true) {
|
||||||
|
@ -23,14 +23,14 @@ class SQLQueryTest extends SapphireTest {
|
|||||||
|
|
||||||
function testSelectFromUserSpecifiedFields() {
|
function testSelectFromUserSpecifiedFields() {
|
||||||
$query = new SQLQuery();
|
$query = new SQLQuery();
|
||||||
$query->select = array("Name", "Title", "Description");
|
$query->select(array("Name", "Title", "Description"));
|
||||||
$query->from[] = "MyTable";
|
$query->from[] = "MyTable";
|
||||||
$this->assertEquals("SELECT Name, Title, Description FROM MyTable", $query->sql());
|
$this->assertEquals("SELECT Name, Title, Description FROM MyTable", $query->sql());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSelectWithWhereClauseFilter() {
|
function testSelectWithWhereClauseFilter() {
|
||||||
$query = new SQLQuery();
|
$query = new SQLQuery();
|
||||||
$query->select = array("Name","Meta");
|
$query->select(array("Name","Meta"));
|
||||||
$query->from[] = "MyTable";
|
$query->from[] = "MyTable";
|
||||||
$query->where[] = "Name = 'Name'";
|
$query->where[] = "Name = 'Name'";
|
||||||
$query->where[] = "Meta = 'Test'";
|
$query->where[] = "Meta = 'Test'";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user