Permalink
Browse files

A symptomatic fix for #2722

When a query is executed twice, for example qhen cloned or when marked
as dirty, it will run the contain process again. This is potentially
dangerous and confusing for some users. The best solution we have for
now is to discourage users from resuing a query that was executed before
until we find a proper way of handling this case.
  • Loading branch information...
1 parent 137ada4 commit 851e5910bd3029e10b9f563e52492713dbc2ebcd @lorenzo lorenzo committed Jan 28, 2014
View
@@ -659,20 +659,22 @@ public function join($tables = null, $types = [], $overwrite = false) {
$types += $this->defaultTypes();
$joins = [];
+ $i = count($this->_parts['join']);
foreach ($tables as $alias => $t) {
if (!is_array($t)) {
$t = ['table' => $t, 'conditions' => $this->newExpr()];
}
if (!($t['conditions']) instanceof ExpressionInterface) {
$t['conditions'] = $this->newExpr()->add($t['conditions'], $types);
}
- $joins[] = $t + ['type' => 'INNER', 'alias' => is_string($alias) ? $alias : null];
+ $alias = is_string($alias) ? $alias : null;
+ $joins[$alias ?: $i++] = $t + ['type' => 'INNER', 'alias' => $alias];
}
if ($overwrite) {
$this->_parts['join'] = $joins;
} else {
- $this->_parts['join'] = array_merge($this->_parts['join'], array_values($joins));
+ $this->_parts['join'] = array_merge($this->_parts['join'], $joins);
}
$this->_dirty();
@@ -703,7 +703,7 @@ public function testEagerLoaderSubquery() {
$expected = clone $parent;
$joins = $expected->join();
- unset($joins[1]);
+ unset($joins['bar']);
$expected
->contain([], true)
->select(['Articles__id' => 'Articles.id'], true)
@@ -335,7 +335,7 @@ public function testEagerLoaderSubquery() {
$expected = clone $parent;
$joins = $expected->join();
- unset($joins[1]);
+ unset($joins['bar']);
$expected
->contain([], true)
->select(['Authors__id' => 'Authors.id'], true)
@@ -999,7 +999,7 @@ public function testApplyOptions() {
$expected = new QueryExpression(['a > b']);
$result = $query->clause('join');
$this->assertEquals([
- ['alias' => 'table_a', 'type' => 'INNER', 'conditions' => $expected]
+ 'table_a' => ['alias' => 'table_a', 'type' => 'INNER', 'conditions' => $expected]
], $result);
$expected = new OrderByExpression(['a' => 'ASC']);
@@ -1818,4 +1818,23 @@ public function testQueryWithStackedFormatters() {
$this->assertEquals($expected, $query->toArray());
}
+/**
+ * Tests that getting results from a query having a contained association
+ * will no attach joins twice if count() is called on it afterwards
+ *
+ * @return void
+ */
+ public function testCountWithContainCallingAll() {
+ $table = TableRegistry::get('articles');
+ $table->belongsTo('authors');
+ $query = $table->find()
+ ->select(['id', 'title'])
+ ->contain('authors')
+ ->limit(2);
+
+ $results = $query->all();
+ $this->assertCount(2, $results);
+ $this->assertEquals(3, $query->count());
+ }
+
}

2 comments on commit 851e591

Owner

markstory commented on 851e591 Jan 29, 2014

Would keeping track of the containments being processed be a reasonable way of tracking and preventing this issue? That value could be invalidated when contain() or join() is called.

Owner

lorenzo replied Jan 29, 2014

I would help to some extent, that would definitely be part of a complete solution. My major concern is what happens if the second time a query is executed, the contain conditions, fields or anything related to them changed substantially, for example removing one of them should also remove the join(s) it attached.

Please sign in to comment.