From 9718d5cd0de681c75a667efaa4076cbaab035380 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 17 Aug 2012 09:02:32 -0500 Subject: [PATCH] fix nested queries. --- laravel/database/eloquent/query.php | 31 +++++++++---------- laravel/database/query.php | 48 +++++++++++++++++++---------- laravel/documentation/changes.md | 14 ++++++--- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/laravel/database/eloquent/query.php b/laravel/database/eloquent/query.php index fa739d55..3aee79c9 100644 --- a/laravel/database/eloquent/query.php +++ b/laravel/database/eloquent/query.php @@ -38,7 +38,7 @@ class Query { ); /** - * Create a new query instance for a model. + * Creat a new query instance for a model. * * @param Model $model * @return void @@ -118,7 +118,7 @@ public function hydrate($model, $results) $new = new $class(array(), true); // We need to set the attributes manually in case the accessible property is - // set on the array which will prevent the mass assignment of attributes if + // set on the array which will prevent the mass assignemnt of attributes if // we were to pass them in using the constructor or fill methods. $new->fill_raw($result); @@ -141,7 +141,7 @@ public function hydrate($model, $results) } } - // The many to many relationships may have pivot table columns on them + // The many to many relationships may have pivot table column on them // so we will call the "clean" method on the relationship to remove // any pivot columns that are on the model. if ($this instanceof Relationships\Has_Many_And_Belongs_To) @@ -199,7 +199,7 @@ protected function nested_includes($relationship) foreach ($this->model_includes() as $include => $constraints) { // To get the nested includes, we want to find any includes that begin - // the relationship with a dot, then we will strip off the leading + // the relationship and a dot, then we will strip off the leading // nesting indicator and set the include in the array. if (starts_with($include, $relationship.'.')) { @@ -217,23 +217,22 @@ protected function nested_includes($relationship) */ protected function model_includes() { - $relationships = array_keys($this->model->includes); - $implicits = array(); + $includes = array(); - foreach ($relationships as $relationship) + foreach ($this->model->includes as $relationship => $constraints) { - $parts = explode('.', $relationship); - - $prefix = ''; - foreach ($parts as $part) + // When eager loading relationships, constraints may be set on the eager + // load definition; however, is none are set, we need to swap the key + // and the value of the array since there are no constraints. + if (is_numeric($relationship)) { - $implicits[$prefix.$part] = NULL; - $prefix .= $part.'.'; + list($relationship, $constraints) = array($constraints, null); } + + $includes[$relationship] = $constraints; } - // Add all implicit includes to the explicit ones - return $this->model->includes + $implicits; + return $includes; } /** @@ -278,4 +277,4 @@ public function __call($method, $parameters) return $this; } -} +} \ No newline at end of file diff --git a/laravel/database/query.php b/laravel/database/query.php index c77ad65b..83c92b83 100644 --- a/laravel/database/query.php +++ b/laravel/database/query.php @@ -2,7 +2,7 @@ use Closure; use Laravel\Database; -use Paginator; +use Laravel\Paginator; use Laravel\Database\Query\Grammars\Postgres; use Laravel\Database\Query\Grammars\SQLServer; @@ -140,7 +140,7 @@ public function distinct() */ public function select($columns = array('*')) { - $this->selects = is_array($columns) ? $columns : array($columns); + $this->selects = (array) $columns; return $this; } @@ -158,7 +158,7 @@ public function join($table, $column1, $operator = null, $column2 = null, $type { // If the "column" is really an instance of a Closure, the developer is // trying to create a join with a complex "ON" clause. So, we will add - // the join, and then call the Closure with the join. + // the join, and then call the Closure with the join/ if ($column1 instanceof Closure) { $this->joins[] = new Query\Join($type, $table); @@ -168,7 +168,7 @@ public function join($table, $column1, $operator = null, $column2 = null, $type // If the column is just a string, we can assume that the join just // has a simple on clause, and we'll create the join instance and - // add the clause automatically for the developer. + // add the clause automatically for the develoepr. else { $join = new Query\Join($type, $table); @@ -283,7 +283,7 @@ public function or_where($column, $operator = null, $value = null) */ public function or_where_id($value) { - return $this->or_where('id', '=', $value); + return $this->or_where('id', '=', $value); } /** @@ -395,7 +395,7 @@ public function or_where_not_null($column) } /** - * Add nested constraints to the query. + * Add a nested where condition to the query. * * @param Closure $callback * @param string $connector @@ -403,7 +403,24 @@ public function or_where_not_null($column) */ public function where_nested($callback, $connector = 'AND') { - call_user_func($callback, $this); + $type = 'where_nested'; + + // To handle a nested where statement, we will actually instantiate a new + // Query instance and run the callback over that instance, which will + // allow the developer to have a fresh query instance + $query = new Query($this->connection, $this->grammar, $this->from); + + call_user_func($callback, $query); + + // Once the callback has been run on the query, we will store the nested + // query instance on the where clause array so that it's passed to the + // query's query grammar instance when building. + if ($query->wheres !== null) + { + $this->wheres[] = compact('type', 'query', 'connector'); + } + + $this->bindings = array_merge($this->bindings, $query->bindings); return $this; } @@ -436,7 +453,7 @@ private function dynamic_where($method, $parameters) foreach ($segments as $segment) { - // If the segment is not a boolean connector, we can assume it is + // If the segment is not a boolean connector, we can assume it it is // a column name, and we'll add it to the query as a new constraint // of the query's where clause and keep iterating the segments. if ($segment != '_and_' and $segment != '_or_') @@ -475,7 +492,6 @@ public function group_by($column) * @param string $column * @param string $operator * @param mixed $value - * @return Query */ public function having($column, $operator, $value) { @@ -660,7 +676,7 @@ public function get($columns = array('*')) public function aggregate($aggregator, $columns) { // We'll set the aggregate value so the grammar does not try to compile - // a SELECT clause on the query. If an aggregator is present, its own + // a SELECT clause on the query. If an aggregator is present, it's own // grammar function will be used to build the SQL syntax. $this->aggregate = compact('aggregator', 'columns'); @@ -687,7 +703,7 @@ public function paginate($per_page = 20, $columns = array('*')) { // Because some database engines may throw errors if we leave orderings // on the query when retrieving the total number of records, we'll drop - // all of the orderings and put them back on the query. + // all of the ordreings and put them back on the query. list($orderings, $this->orderings) = array($this->orderings, null); $total = $this->count(reset($columns)); @@ -714,12 +730,12 @@ public function insert($values) { // Force every insert to be treated like a batch insert to make creating // the binding array simpler since we can just spin through the inserted - // rows as if there was more than one every time. + // rows as if there/ was more than one every time. if ( ! is_array(reset($values))) $values = array($values); $bindings = array(); - // We need to merge the insert values into the array of the query + // We need to merge the the insert values into the array of the query // bindings so that they will be bound to the PDO statement when it // is executed by the database connection. foreach ($values as $value) @@ -820,7 +836,7 @@ public function update($values) /** * Execute the query as a DELETE statement. * - * Optionally, an ID may be passed to the method to delete a specific row. + * Optionally, an ID may be passed to the method do delete a specific row. * * @param int $id * @return int @@ -837,7 +853,7 @@ public function delete($id = null) $sql = $this->grammar->delete($this); - return $this->connection->query($sql, $this->bindings); + return $this->connection->query($sql, $this->bindings); } /** @@ -853,7 +869,7 @@ public function __call($method, $parameters) } // All of the aggregate methods are handled by a single method, so we'll - // catch them all here and then pass them off to the aggregate method + // catch them all here and then pass them off to the agregate method // instead of creating methods for each one of them. if (in_array($method, array('count', 'min', 'max', 'avg', 'sum'))) { diff --git a/laravel/documentation/changes.md b/laravel/documentation/changes.md index 7f70c817..5ff87c38 100644 --- a/laravel/documentation/changes.md +++ b/laravel/documentation/changes.md @@ -2,7 +2,8 @@ # Laravel Change Log ## Contents -- [Develop](#develop) +- [Laravel 3.2.5](#3.2.5) +- [Upgrading From 3.2.4](#upgrade-3.2.5) - [Laravel 3.2.4](#3.2.4) - [Upgrading From 3.2.3](#upgrade-3.2.4) - [Laravel 3.2.3](#3.2.3) @@ -34,11 +35,14 @@ ## Contents - [Laravel 3.1](#3.1) - [Upgrading From 3.0](#upgrade-3.1) - -## Develop + -- Added Turkish language files. -- Changed jQuery '$' to 'jQuery' in the Profiler. +- Revert nested where code back to 3.2.3 tag. + + +## Upgrading From 3.2.4 + +- Replace the **laravel** folder. ## Laravel 3.2.4