Skip to content

Commit

Permalink
Merge pull request silverstripe#400 from halkyon/sqlquery_enhancements
Browse files Browse the repository at this point in the history
API CHANGE Deprecated internal access to SQLQuery properties
  • Loading branch information
sminnee committed May 7, 2012
2 parents 4e18cc5 + 051d9de commit 07bd8e5
Show file tree
Hide file tree
Showing 13 changed files with 674 additions and 409 deletions.
6 changes: 3 additions & 3 deletions core/PaginatedList.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ public function setTotalItems($items) {
* @param SQLQuery $query
*/
public function setPaginationFromQuery(SQLQuery $query) {
if ($query->limit) {
$this->setPageLength($query->limit['limit']);
$this->setPageStart($query->limit['start']);
if ($limit = $query->getLimit()) {
$this->setPageLength($limit['limit']);
$this->setPageStart($limit['start']);
$this->setTotalItems($query->unlimitedRowCount());
}
}
Expand Down
21 changes: 21 additions & 0 deletions docs/en/changelogs/3.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,27 @@ The abstract `RelationList` class and its implementations `ManyManyList` and `Ha
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).

### `SQLQuery` changes ###

`SQLQuery` has been changed so direct access to internal properties `$from`, `$select`, `$orderby` is
now deprecated.

Instead, there are now methods you can call which allow you to get and set SQL clauses instead.

* `$from` getter is `getFrom()` and setters `setFrom()` and `addFrom()`
* `$select` getter is `getSelect()` and setters `setSelect()` and `addSelect()`
* `$where` getter is `getWhere()` and setter `setWhere()` and `addWhere()`
* `$orderby` getter is `getOrderBy()` and setter `setOrderBy()` and `addOrderBy()`
* `$groupby` getter is `getGroupBy()` and setter `getGroupBy()` and `addGroupBy()`
* `$having` getter is `getHaving()` and setter `setHaving()` and `addHaving()`
* `$limit` getter is `getLimit()` and setter `setLimit()`
* `$distinct` getter is `getDistinct()` and setter `setDistinct()`
* `$delete` getter is `getDelete()` and setter `setDelete()`
* `$connective` getter is `getConnective()` and settter `setConnective()`

* `innerJoin()` has been renamed to `addInnerJoin()`
* `leftJoin()` has been renamed to `addLeftJoin()`

### InnoDB driver for existing and new tables on MySQL (instead of MyISAM) [innodb]###

SilverStripe has traditionally created all MySQL tables with the MyISAM storage driver,
Expand Down
2 changes: 1 addition & 1 deletion model/DataList.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public function sort() {

return $this;
}

/**
* Filter the list to include items with these charactaristics
*
Expand Down
6 changes: 3 additions & 3 deletions model/DataObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -1216,9 +1216,9 @@ public function delete() {
// obviously, that means getting requireTable() to configure cascading deletes ;-)
$srcQuery = DataList::create($this->class, $this->model)->where("ID = $this->ID")->dataQuery()->query();
foreach($srcQuery->queriedTables() as $table) {
$query = new SQLQuery("*", array('"'.$table.'"'));
$query->where("\"ID\" = $this->ID");
$query->delete = true;
$query = new SQLQuery("*", array('"' . $table . '"'));
$query->setWhere("\"ID\" = $this->ID");
$query->setDelete(true);
$query->execute();
}
// Remove this item out of any caches
Expand Down
105 changes: 55 additions & 50 deletions model/DataQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function __clone() {
* Return the {@link DataObject} class that is being queried.
*/
function dataClass() {
return $this->dataClass;
return $this->dataClass;
}

/**
Expand All @@ -75,15 +75,22 @@ function query() {
*/
function removeFilterOn($fieldExpression) {
$matched = false;
foreach($this->query->where as $i=>$item) {
if(strpos($item, $fieldExpression) !== false) {
unset($this->query->where[$i]);

$where = $this->query->getWhere();
foreach($where as $i => $clause) {
if(strpos($clause, $fieldExpression) !== false) {
unset($where[$i]);
$matched = true;
}
}

if(!$matched) throw new InvalidArgumentException("Couldn't find $fieldExpression in the query filter.");


// set the entire where clause back, but clear the original one first
if($matched) {
$this->query->setWhere($where);
} else {
throw new InvalidArgumentException("Couldn't find $fieldExpression in the query filter.");
}

return $this;
}

Expand All @@ -108,13 +115,13 @@ function initialiseQuery() {

// Build our intial query
$this->query = new SQLQuery(array());
$this->query->distinct = true;
$this->query->setDistinct(true);

if($sort = singleton($this->dataClass)->stat('default_sort')) {
$this->sort($sort);
}

$this->query->from("\"$baseClass\"");
$this->query->setFrom("\"$baseClass\"");

singleton($this->dataClass)->extend('augmentDataQueryCreation', $this->query, $this);
}
Expand All @@ -140,7 +147,7 @@ function getFinalisedQuery($queriedColumns = null) {
if($queriedColumns) {
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);

foreach ($query->where as $where) {
foreach ($query->getWhere() as $where) {
// Check for just the column, in the form '"Column" = ?' and the form '"Table"."Column"' = ?
if (preg_match('/^"([^"]+)"/', $where, $matches) ||
preg_match('/^"([^"]+)"\."[^"]+"/', $where, $matches)) {
Expand Down Expand Up @@ -179,7 +186,7 @@ function getFinalisedQuery($queriedColumns = null) {
}

if ($joinTable) {
$query->leftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"") ;
$query->addLeftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"") ;
}
}

Expand Down Expand Up @@ -208,7 +215,7 @@ function getFinalisedQuery($queriedColumns = null) {
// Get the ClassName values to filter to
$classNames = ClassInfo::subclassesFor($this->dataClass);
if(!$classNames) user_error("DataList::create() Can't find data sub-classes for '$callerClass'");
$query->where[] = "\"$baseClass\".\"ClassName\" IN ('" . implode("','", $classNames) . "')";
$query->addWhere("\"$baseClass\".\"ClassName\" IN ('" . implode("','", $classNames) . "')");
}
}

Expand All @@ -233,9 +240,7 @@ protected function ensureSelectContainsOrderbyColumns($query, $originalSelect =
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
$baseClass = array_shift($tableClasses);

if($query->orderby) {
$orderby = $query->getOrderBy();

if($orderby = $query->getOrderBy()) {
foreach($orderby as $k => $dir) {
// don't touch functions in the ORDER BY or function calls
// selected as fields
Expand Down Expand Up @@ -270,23 +275,24 @@ protected function ensureSelectContainsOrderbyColumns($query, $originalSelect =
$qualCol = "\"$parts[0]\"";
}

// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
// To-do: Remove this if block once SQLQuery::$select has been refactored to store getSelect()
// format internally; then this check can be part of selectField()
if(!isset($query->select[$col]) && !in_array($qualCol, $query->select)) {
$selects = $query->getSelect();
if(!isset($selects[$col]) && !in_array($qualCol, $selects)) {
$query->selectField($qualCol);
}
} else {
$qualCol = '"' . implode('"."', $parts) . '"';

// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
// To-do: Remove this if block once SQLQuery::$select has been refactored to store getSelect()
// format internally; then this check can be part of selectField()
if(!in_array($qualCol, $query->select)) {
if(!in_array($qualCol, $query->getSelect())) {
$query->selectField($qualCol);
}
}
}

$query->orderby = $orderby;
$query->setOrderBy($orderby);
}
}

Expand Down Expand Up @@ -390,7 +396,7 @@ protected function selectColumnsFromTable(SQLQuery &$query, $tableClass, $column
function having($having) {
if($having) {
$clone = $this;
$clone->query->having[] = $having;
$clone->query->addHaving($having);
return $clone;
} else {
return $this;
Expand All @@ -403,7 +409,7 @@ function having($having) {
function where($filter) {
if($filter) {
$clone = $this;
$clone->query->where($filter);
$clone->query->addWhere($filter);
return $clone;
} else {
return $this;
Expand Down Expand Up @@ -436,7 +442,11 @@ function whereAny($filter) {
*/
function sort($sort = null, $direction = null, $clear = true) {
$clone = $this;
$clone->query->orderby($sort, $direction, $clear);
if($clear) {
$clone->query->setOrderBy($sort, $direction);
} else {
$clone->query->addOrderBy($sort, $direction);
}

return $clone;
}
Expand All @@ -458,7 +468,7 @@ function reverseSort() {
*/
function limit($limit, $offset = 0) {
$clone = $this;
$clone->query->limit($limit, $offset);
$clone->query->setLimit($limit, $offset);
return $clone;
}

Expand All @@ -470,9 +480,13 @@ function join($join) {
Deprecation::notice('3.0', 'Use innerJoin() or leftJoin() instead.');
if($join) {
$clone = $this;
$clone->query->from[] = $join;
$clone->query->addFrom($join);
// TODO: This needs to be resolved for all databases
if(DB::getConn() instanceof MySQLDatabase) $clone->query->groupby[] = reset($clone->query->from) . ".\"ID\"";

if(DB::getConn() instanceof MySQLDatabase) {
$from = $clone->query->getFrom();
$clone->query->setGroupBy(reset($from) . ".\"ID\"");
}
return $clone;
} else {
return $this;
Expand All @@ -487,7 +501,7 @@ function join($join) {
public function innerJoin($table, $onClause, $alias = null) {
if($table) {
$clone = $this;
$clone->query->innerJoin($table, $onClause, $alias);
$clone->query->addInnerJoin($table, $onClause, $alias);
return $clone;
} else {
return $this;
Expand All @@ -502,7 +516,7 @@ public function innerJoin($table, $onClause, $alias = null) {
public function leftJoin($table, $onClause, $alias = null) {
if($table) {
$clone = $this;
$clone->query->leftJoin($table, $onClause, $alias);
$clone->query->addLeftJoin($table, $onClause, $alias);
return $clone;
} else {
return $this;
Expand Down Expand Up @@ -530,7 +544,7 @@ function applyRelation($relation) {
if ($component = $model->has_one($rel)) {
if(!$this->query->isJoinedTo($component)) {
$foreignKey = $model->getReverseAssociation($component);
$this->query->leftJoin($component, "\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");
$this->query->addLeftJoin($component, "\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");

/**
* add join clause to the component's ancestry classes so that the search filter could search on its
Expand All @@ -541,7 +555,7 @@ function applyRelation($relation) {
$ancestry = array_reverse($ancestry);
foreach($ancestry as $ancestor){
if($ancestor != $component){
$this->query->innerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
$component=$ancestor;
}
}
Expand All @@ -553,7 +567,7 @@ function applyRelation($relation) {
if(!$this->query->isJoinedTo($component)) {
$ancestry = $model->getClassAncestry();
$foreignKey = $model->getRemoteJoinField($rel);
$this->query->leftJoin($component, "\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
$this->query->addLeftJoin($component, "\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
/**
* add join clause to the component's ancestry classes so that the search filter could search on its
* ancestor fields.
Expand All @@ -563,7 +577,7 @@ function applyRelation($relation) {
$ancestry = array_reverse($ancestry);
foreach($ancestry as $ancestor){
if($ancestor != $component){
$this->query->innerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
$component=$ancestor;
}
}
Expand All @@ -575,10 +589,10 @@ function applyRelation($relation) {
list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component;
$parentBaseClass = ClassInfo::baseDataClass($parentClass);
$componentBaseClass = ClassInfo::baseDataClass($componentClass);
$this->query->innerJoin($relationTable, "\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
$this->query->leftJoin($componentBaseClass, "\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
$this->query->addInnerJoin($relationTable, "\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
$this->query->addLeftJoin($componentBaseClass, "\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
if(ClassInfo::hasTable($componentClass)) {
$this->query->leftJoin($componentClass, "\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
$this->query->addLeftJoin($componentClass, "\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
}
$modelClass = $componentClass;

Expand All @@ -597,7 +611,7 @@ function applyRelation($relation) {
public function subtract(DataQuery $subtractQuery, $field='ID') {
$subSelect= $subtractQuery->getFinalisedQuery();
$fieldExpression = $this->expressionForField($field, $subSelect);
$subSelect->clearSelect();
$subSelect->setSelect(array());
$subSelect->selectField($fieldExpression, $field);
$this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')');

Expand All @@ -611,7 +625,7 @@ public function selectFromTable($table, $fields) {
$fieldExpressions = array_map(create_function('$item',
"return '\"$table\".\"' . \$item . '\"';"), $fields);

$this->query->select($fieldExpressions);
$this->query->setSelect($fieldExpressions);

return $this;
}
Expand All @@ -621,9 +635,9 @@ public function selectFromTable($table, $fields) {
*/
public function column($field = 'ID') {
$query = $this->getFinalisedQuery(array($field));
$originalSelect = $query->itemisedSelect();
$originalSelect = $query->getSelect();
$fieldExpression = $this->expressionForField($field, $query);
$query->clearSelect();
$query->setSelect(array());
$query->selectField($fieldExpression, $field);
$this->ensureSelectContainsOrderbyColumns($query, $originalSelect);

Expand All @@ -637,17 +651,8 @@ protected function expressionForField($field, $query) {
return "\"$baseClass\".\"ID\"";

} else {
return $query->expressionForField($field);
}
}

/**
* Clear the selected fields to start over
*/
public function clearSelect() {
$this->query->clearSelect();

return $this;
return $query->expressionForField($field);
}
}

/**
Expand Down
Loading

0 comments on commit 07bd8e5

Please sign in to comment.