Browse Source

Exclude features from count queries with eagerloader features.

Instead of rewriting contain() options we should use eagerloader
features to exclude associated fields from count queries.
Mark Story 11 years ago
parent
commit
4d0bbe4e43
4 changed files with 52 additions and 10 deletions
  1. 5 0
      src/ORM/Association.php
  2. 24 1
      src/ORM/EagerLoader.php
  3. 1 8
      src/ORM/Query.php
  4. 22 1
      tests/TestCase/ORM/QueryTest.php

+ 5 - 0
src/ORM/Association.php

@@ -640,6 +640,11 @@ abstract class Association
         $fields = $surrogate->clause('select') ?: $options['fields'];
         $fields = $surrogate->clause('select') ?: $options['fields'];
         $target = $this->_targetTable;
         $target = $this->_targetTable;
         $autoFields = $surrogate->autoFields();
         $autoFields = $surrogate->autoFields();
+
+        if ($query->eagerLoader()->autoFields() === false) {
+            return false;
+        }
+
         if (empty($fields) && !$autoFields) {
         if (empty($fields) && !$autoFields) {
             if ($options['includeFields'] && ($fields === null || $fields !== false)) {
             if ($options['includeFields'] && ($fields === null || $fields !== false)) {
                 $fields = $target->schema()->columns();
                 $fields = $target->schema()->columns();

+ 24 - 1
src/ORM/EagerLoader.php

@@ -96,6 +96,15 @@ class EagerLoader
     protected $_joinsMap = [];
     protected $_joinsMap = [];
 
 
     /**
     /**
+     * Controls whether or not fields from associated tables
+     * will be eagerly loaded. When set to false, no fields will
+     * be loaded from associations.
+     *
+     * @var bool
+     */
+    protected $_autoFields = true;
+
+    /**
      * Sets the list of associations that should be eagerly loaded along for a
      * Sets the list of associations that should be eagerly loaded along for a
      * specific table using when a query is provided. The list of associated tables
      * specific table using when a query is provided. The list of associated tables
      * passed to this method must have been previously set as associations using the
      * passed to this method must have been previously set as associations using the
@@ -135,6 +144,20 @@ class EagerLoader
     }
     }
 
 
     /**
     /**
+     * Set whether or not contained associations will load fields automatically.
+     *
+     * @param bool $value The value to set.
+     * @return bool The current value.
+     */
+    public function autoFields($value = null)
+    {
+        if ($value !== null) {
+            $this->_autoFields = (bool)$value;
+        }
+        return $this->_autoFields;
+    }
+
+    /**
      * Adds a new association to the list that will be used to filter the results of
      * Adds a new association to the list that will be used to filter the results of
      * any given query based on the results of finding records for that association.
      * any given query based on the results of finding records for that association.
      * You can pass a dot separated path of associations to this method as its first
      * You can pass a dot separated path of associations to this method as its first
@@ -294,7 +317,7 @@ class EagerLoader
             $config = $loadable->config() + [
             $config = $loadable->config() + [
                 'aliasPath' => $loadable->aliasPath(),
                 'aliasPath' => $loadable->aliasPath(),
                 'propertyPath' => $loadable->propertyPath(),
                 'propertyPath' => $loadable->propertyPath(),
-                'includeFields' => $includeFields
+                'includeFields' => $includeFields,
             ];
             ];
             $loadable->instance()->attachTo($query, $config);
             $loadable->instance()->attachTo($query, $config);
         }
         }

+ 1 - 8
src/ORM/Query.php

@@ -507,16 +507,9 @@ class Query extends DatabaseQuery implements JsonSerializable
         $complex = $complex || count($query->clause('union'));
         $complex = $complex || count($query->clause('union'));
 
 
         if (!$complex) {
         if (!$complex) {
-            $cleanContain = [];
-            foreach ($query->contain() as $alias => $contain) {
-                unset($contain['fields']);
-                $cleanContain[$alias] = $contain;
-            }
-            $query->contain(null, true);
-
+            $query->eagerLoader()->autoFields(false);
             $statement = $query
             $statement = $query
                 ->select($count, true)
                 ->select($count, true)
-                ->contain($cleanContain)
                 ->autoFields(false)
                 ->autoFields(false)
                 ->execute();
                 ->execute();
         } else {
         } else {

+ 22 - 1
tests/TestCase/ORM/QueryTest.php

@@ -1446,6 +1446,27 @@ class QueryTest extends TestCase
     }
     }
 
 
     /**
     /**
+     * Test getting counts from queries with contain.
+     *
+     * @return void
+     */
+    public function testCountWithContain()
+    {
+        $table = TableRegistry::get('Articles');
+        $table->belongsTo('Authors');
+
+        $result = $table->find('all')
+            ->contain([
+                'Authors' => [
+                    'fields' => ['name']
+                ]
+            ])
+            ->count();
+        $this->assertSame(3, $result);
+    }
+
+
+    /**
      * test count with a beforeFind.
      * test count with a beforeFind.
      *
      *
      * @return void
      * @return void
@@ -1871,7 +1892,7 @@ class QueryTest extends TestCase
 
 
     /**
     /**
      * Tests that getting results from a query having a contained association
      * Tests that getting results from a query having a contained association
-     * will no attach joins twice if count() is called on it afterwards
+     * will not attach joins twice if count() is called on it afterwards
      *
      *
      * @return void
      * @return void
      */
      */