Просмотр исходного кода

[translatable] fix and improve translation query walker, closes #173

gediminasm 13 лет назад
Родитель
Сommit
979a99882c

+ 0 - 22
lib/Gedmo/Translatable/Hydrator/ORM/ArrayHydrator.php

@@ -1,22 +0,0 @@
-<?php
-
-namespace Gedmo\Translatable\Hydrator\ORM;
-
-use Gedmo\Translatable\Query\TreeWalker\TranslationWalker;
-use Doctrine\ORM\Internal\Hydration\ArrayHydrator as BaseArrayHydrator;
-
-/**
- * If query uses TranslationQueryWalker and is hydrating
- * objects - when it requires this custom object hydrator
- * in order to skip onLoad event from triggering retranslation
- * of the fields
- *
- * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
- * @package Gedmo.Translatable.Hydrator.ORM
- * @subpackage ObjectHydrator
- * @link http://www.gediminasm.org
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-class ArrayHydrator extends BaseArrayHydrator
-{
-}

+ 36 - 25
lib/Gedmo/Translatable/Query/TreeWalker/TranslationWalker.php

@@ -9,6 +9,8 @@ use Doctrine\ORM\Query\SqlWalker;
 use Doctrine\ORM\Query\TreeWalkerAdapter;
 use Doctrine\ORM\Query\AST\SelectStatement;
 use Doctrine\ORM\Query\Exec\SingleSelectExecutor;
+use Doctrine\ORM\Query\AST\RangeVariableDeclaration;
+use Doctrine\ORM\Query\AST\Join;
 
 /**
  * The translation sql output walker makes it possible
@@ -91,19 +93,11 @@ class TranslationWalker extends SqlWalker
     private $replacements = array();
 
     /**
-     * Translation joins on current query
-     * components
+     * List of joins for translated components in query
      *
      * @var array
      */
-    private $translationJoinSql = array();
-
-    /**
-     * Processed subselect number
-     *
-     * @var integer
-     */
-    private $processedNestingLevel = 0;
+    private $components = array();
 
     /**
      * {@inheritDoc}
@@ -125,7 +119,7 @@ class TranslationWalker extends SqlWalker
         if (!$AST instanceof SelectStatement) {
             throw new \Gedmo\Exception\UnexpectedValueException('Translation walker should be used only on select statement');
         }
-        $this->translationJoinSql = $this->getTranslationJoinsSql();
+        $this->prepareTranslatedComponents();
         return new SingleSelectExecutor($AST, $this);
     }
 
@@ -176,9 +170,7 @@ class TranslationWalker extends SqlWalker
     public function walkFromClause($fromClause)
     {
         $result = parent::walkFromClause($fromClause);
-        if (count($this->translationJoinSql)) {
-            $result .= $this->translationJoinSql[0];
-        }
+        $result .= $this->joinTranslations($fromClause);
         return $result;
     }
 
@@ -214,7 +206,6 @@ class TranslationWalker extends SqlWalker
      */
     public function walkSubselect($subselect)
     {
-        $this->processedNestingLevel++;
         $result = parent::walkSubselect($subselect);
         return $result;
     }
@@ -225,9 +216,7 @@ class TranslationWalker extends SqlWalker
     public function walkSubselectFromClause($subselectFromClause)
     {
         $result = parent::walkSubselectFromClause($subselectFromClause);
-        if (isset($this->translationJoinSql[$this->processedNestingLevel])) {
-            $result .= $this->translationJoinSql[$this->processedNestingLevel];
-        }
+        $result .= $this->joinTranslations($subselectFromClause);
         return $result;
     }
 
@@ -240,6 +229,33 @@ class TranslationWalker extends SqlWalker
         return $this->replace($this->replacements, $result);
     }
 
+    /**
+     * Walks from clause, and creates translation joins
+     * for the translated components
+     *
+     * @param Doctrine\ORM\Query\AST\FromClause $from
+     * @return string
+     */
+    private function joinTranslations($from)
+    {
+        $result = '';
+        foreach ($from->identificationVariableDeclarations as $decl) {
+            if ($decl->rangeVariableDeclaration instanceof RangeVariableDeclaration) {
+                if (isset($this->components[$decl->rangeVariableDeclaration->aliasIdentificationVariable])) {
+                    $result .= $this->components[$decl->rangeVariableDeclaration->aliasIdentificationVariable];
+                }
+            }
+            foreach ($decl->joinVariableDeclarations as $joinDecl) {
+                if ($joinDecl->join instanceof Join) {
+                    if (isset($this->components[$joinDecl->join->aliasIdentificationVariable])) {
+                        $result .= $this->components[$joinDecl->join->aliasIdentificationVariable];
+                    }
+                }
+            }
+        }
+        return $result;
+    }
+
     /**
      * Creates a left join list for translations
      * on used query components
@@ -247,18 +263,14 @@ class TranslationWalker extends SqlWalker
      * @todo: make it cleaner
      * @return string
      */
-    private function getTranslationJoinsSql()
+    private function prepareTranslatedComponents()
     {
-        $result = array();
         $em = $this->getEntityManager();
         $ea = new TranslatableEventAdapter;
         $locale = $this->listener->getListenerLocale();
         $defaultLocale = $this->listener->getDefaultLocale();
 
         foreach ($this->translatedComponents as $dqlAlias => $comp) {
-            if (!isset($result[$comp['nestingLevel']])) {
-                $result[$comp['nestingLevel']] = '';
-            }
             $meta = $comp['metadata'];
             $config = $this->listener->getConfiguration($em, $meta->name);
             $transClass = $this->listener->getTranslationClass($ea, $meta->name);
@@ -280,7 +292,7 @@ class TranslationWalker extends SqlWalker
                     $colName = $meta->getQuotedColumnName($identifier, $this->platform);
                     $sql .= ' AND '.$tblAlias.'.'.$transMeta->getQuotedColumnName('foreignKey', $this->platform)
                         .' = '.$compTblAlias.'.'.$colName;
-                    $result[$comp['nestingLevel']] .= $sql;
+                    isset($this->components[$dqlAlias]) ? $this->components[$dqlAlias] .= $sql : $this->components[$dqlAlias] = $sql;
                     if ($this->needsFallback()) {
                         // COALESCE with the original record columns
                         $this->replacements[$compTblAlias.'.'.$meta->getQuotedColumnName($field, $this->platform)]
@@ -295,7 +307,6 @@ class TranslationWalker extends SqlWalker
                 }
             }
         }
-        return $result;
     }
 
     /**

+ 33 - 24
tests/Gedmo/Translatable/Issue/Issue173Test.php

@@ -4,6 +4,7 @@ namespace Gedmo\Translatable;
 
 use Doctrine\Common\EventManager;
 use Tool\BaseTestCaseORM;
+use Gedmo\Translatable\Query\TreeWalker\TranslationWalker;
 use Translatable\Fixture\Issue173\Article;
 use Translatable\Fixture\Issue173\Category;
 use Translatable\Fixture\Issue173\Product;
@@ -18,12 +19,12 @@ use Translatable\Fixture\Issue173\Product;
  * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  */
 class Issue173Test extends BaseTestCaseORM
-{ 
+{
     const CATEGORY =   'Translatable\\Fixture\\Issue173\\Category';
     const ARTICLE = 'Translatable\\Fixture\\Issue173\\Article';
     const PRODUCT = 'Translatable\\Fixture\\Issue173\\Product';
     const TRANSLATION = 'Gedmo\\Translatable\\Entity\\Translation';
-    
+
     private $translatableListener;
 
     protected function setUp()
@@ -43,9 +44,17 @@ class Issue173Test extends BaseTestCaseORM
 
     public function testIssue173()
     {
+        $this->em
+            ->getConfiguration()
+            ->expects($this->any())
+            ->method('getCustomHydrationMode')
+            ->with(TranslationWalker::HYDRATE_OBJECT_TRANSLATION)
+            ->will($this->returnValue('Gedmo\\Translatable\\Hydrator\\ORM\\ObjectHydrator'))
+        ;
+
         $categories = $this->getCategoriesThatHasNoAssociations();
         $this->assertEquals(count($categories), 1, '$categoriy3 has no associations');
-           
+
     }
 
     public function getCategoriesThatHasNoAssociations()
@@ -54,28 +63,28 @@ class Issue173Test extends BaseTestCaseORM
         $query2 = $this->em->createQueryBuilder();
         $query3 = $this->em->createQueryBuilder();
         $dql1 = $query2
-                    ->select('c1')
-                    ->from(self::CATEGORY, 'c1')
-                    ->join('c1.products', 'p')
-                    ->getDql()
-                ;
+            ->select('c1')
+            ->from(self::CATEGORY, 'c1')
+            ->join('c1.products', 'p')
+            ->getDql()
+        ;
         $dql2 = $query3
-                    ->select('c2')
-                    ->from(self::CATEGORY, 'c2')
-                    ->join('c2.articles', 'a')
-                    ->getDql()
-                ;   
+            ->select('c2')
+            ->from(self::CATEGORY, 'c2')
+            ->join('c2.articles', 'a')
+            ->getDql()
+        ;
         $query
             ->select('c')
             ->from(self::CATEGORY, 'c')
             ->where($query->expr()->notIn('c.id', $dql1))
             ->andWhere($query->expr()->notIn('c.id', $dql2))
-            ; 
-    
+            ;
+
         return $query->getQuery()->setHint(
-                        \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
-                        'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
-                )->getResult();
+            \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
+            'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
+        )->getResult();
     }
 
     private function populate()
@@ -83,10 +92,10 @@ class Issue173Test extends BaseTestCaseORM
         //Categories
         $category1 = new Category;
         $category1->setTitle('en category1');
-    
+
         $category2 = new Category;
         $category2->setTitle('en category2');
-        
+
         $category3 = new Category;
         $category3->setTitle('en category3');
 
@@ -104,13 +113,13 @@ class Issue173Test extends BaseTestCaseORM
         $product1 = new Product;
         $product1->setTitle('en product1');
         $product1->setCategory($category2);
-        
+
         $this->em->persist($article1);
         $this->em->persist($product1);
         $this->em->flush();
 
         $this->translatableListener->setTranslatableLocale('es');
-        
+
         // Categories
         $category1->setTitle('es title');
         $category2->setTitle('es title');
@@ -124,7 +133,7 @@ class Issue173Test extends BaseTestCaseORM
         $this->em->persist($category3);
         $this->em->persist($article1);
         $this->em->persist($product1);
-       
+
         $this->em->flush();
     }
 
@@ -135,7 +144,7 @@ class Issue173Test extends BaseTestCaseORM
             self::ARTICLE,
             self::PRODUCT,
             self::TRANSLATION,
-            
+
         );
     }
 }