Browse Source

support for string type primary keys for translation records added unit tests for dql object hydration test and translation loading

gediminasm 15 years ago
parent
commit
e5d1390a84

+ 4 - 4
lib/DoctrineExtensions/Translatable/Entity/Translation.php

@@ -43,9 +43,9 @@ class Translation
     private $field;
 
     /**
-     * @var integer $foreignKey
+     * @var string $foreignKey
      *
-     * @Column(name="foreign_key", type="integer", nullable=true)
+     * @Column(name="foreign_key", type="string", length="64")
      */
     private $foreignKey;
 
@@ -129,7 +129,7 @@ class Translation
     /**
      * Set foreignKey
      *
-     * @param integer $foreignKey
+     * @param string $foreignKey
      */
     public function setForeignKey($foreignKey)
     {
@@ -139,7 +139,7 @@ class Translation
     /**
      * Get foreignKey
      *
-     * @return integer $foreignKey
+     * @return string $foreignKey
      */
     public function getForeignKey()
     {

+ 0 - 6
lib/DoctrineExtensions/Translatable/Exception.php

@@ -23,12 +23,6 @@ class Exception extends \Exception
         return new self("Only a single identifier column is required for the Translatable extension, entity: {$entityClass}.");
     }
     
-    static public function invalidIdentifierType($id)
-    {
-    	$type = gettype($id);
-        return new self("Currently there is only integer identifiers supported, [{$type}] is given.");
-    }
-    
     static public function pendingInserts()
     {
         return new self("UnitOfWork has pending inserts, cannot request query execution. TranslationListener does not support Concurrent inserts and updates together, on Doctrine 2 Beta4 yet. Try flushing only inserts or updates");

+ 0 - 5
lib/DoctrineExtensions/Translatable/Repository/TranslationRepository.php

@@ -41,11 +41,6 @@ class TranslationRepository extends EntityRepository
 	        } else {
 	            throw Exception::singleIdentifierRequired($entityClass);
 	        }
-	
-	        // @todo: add support for string type identifier also 
-	        if (!is_int($entityId)) {
-	            throw Exception::invalidIdentifierType($entityId);
-	        }
 	        
 	        $qb = $this->_em->createQueryBuilder();
 	        $qb->select('trans.content, trans.field, trans.locale')

+ 21 - 9
lib/DoctrineExtensions/Translatable/TranslationListener.php

@@ -32,7 +32,7 @@ class TranslationListener implements EventSubscriber
 	const TRANSLATION_ENTITY_CLASS = 'DoctrineExtensions\Translatable\Entity\Translation';
 	
 	/**
-	 * Default locale which is set on this listener.
+	 * Locale which is set on this listener.
 	 * If Entity being translated has locale defined it
 	 * will override this one
 	 *  
@@ -159,18 +159,22 @@ class TranslationListener implements EventSubscriber
         // check if entity is Translatable and without foreign key
         if ($entity instanceof Translatable && count($this->_pendingTranslationInserts)) {
         	$oid = spl_object_hash($entity);
+        	$entityClass = get_class($entity);
+            $entityClassMetadata = $em->getClassMetadata($entityClass);
+            // there should be single identifier
+            $identifierField = $entityClassMetadata->getSingleIdentifierFieldName();
+            $identifierGetter = 'get' . ucfirst($identifierField);
         	if (array_key_exists($oid, $this->_pendingTranslationInserts)) {
                 // load the pending translations without key
         		$translations = $this->_pendingTranslationInserts[$oid];
         		foreach ($translations as $translation) {
-	                $translation->setForeignKey($entity->getId());
+	                $translation->setForeignKey($entity->{$identifierGetter}());
 	                $this->_insertTranslationRecord($em, $translation);
         		}
             }
         }
         // all translations which should have been inserted are processed now
         // this prevents new pending insertions during sheduled updates process
-        // and twice queries
         if (!$uow->hasPendingInsertions() && count($this->_pendingTranslationUpdates)) {
         	foreach ($this->_pendingTranslationUpdates as $candidate) {
         		$translation = $this->_findTranslation(
@@ -208,11 +212,16 @@ class TranslationListener implements EventSubscriber
     		$locale = strtolower($this->getTranslatableLocale($entity));
 	    	$this->_validateLocale($locale);
             
+	    	$entityClass = get_class($entity);
+	    	$entityClassMetadata = $em->getClassMetadata($entityClass);
+	    	// there should be single identifier
+	    	$identifierField = $entityClassMetadata->getSingleIdentifierFieldName();
+	    	$identifierGetter = 'get' . ucfirst($identifierField);
 	    	// load translated content for all translatable fields
             foreach ($entity->getTranslatableFields() as $field) {
             	$content = $this->_findTranslation(
             	    $em,
-            	    $entity->getId(),
+            	    $entity->{$identifierGetter}(),
             	    get_class($entity),
                     $locale,
             	    $field,
@@ -254,11 +263,6 @@ class TranslationListener implements EventSubscriber
             throw Exception::singleIdentifierRequired($entityClass);
         }
         
-        // @todo: add support for string type identifier also 
-        if (!is_int($entityId) && !is_null($entityId)) {
-        	throw Exception::invalidIdentifierType($entityId);
-        }
-        
         // load the currently used locale
         $locale = strtolower($this->getTranslatableLocale($entity));
         $this->_validateLocale($locale);
@@ -384,6 +388,14 @@ class TranslationListener implements EventSubscriber
     	}
     }
     
+    /**
+     * Does the standard insert. Which is not managed by entity manager.
+     * 
+     * @param EntityManager $em
+     * @param object $translation
+     * @throws Translatable\Exception if insert fails
+     * @return void
+     */
     private function _insertTranslationRecord(EntityManager $em, $translation)
     {
         $translationMetadata = $em->getClassMetadata(self::TRANSLATION_ENTITY_CLASS);

+ 168 - 0
tests/DoctrineExtensions/Translatable/TranslatableIdentifierTest.php

@@ -0,0 +1,168 @@
+<?php
+
+namespace DoctrineExtensions\Translatable;
+
+use Doctrine\Common\Util\Debug;
+
+/**
+ * These are tests for translatable behavior
+ * 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package DoctrineExtensions.Translatable
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class TranslatableIdentifierTest extends \PHPUnit_Framework_TestCase
+{
+    const TEST_ENTITY_CLASS = 'DoctrineExtensions\Translatable\StringIdentifier';
+    const TRANSLATION_CLASS = 'DoctrineExtensions\Translatable\Entity\Translation';
+    private $testObjectId;
+    private $translationListener;
+    private $em;
+
+    public function setUp()
+    {
+        $config = new \Doctrine\ORM\Configuration();
+        $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
+        $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
+        $config->setProxyDir(__DIR__ . '/temp');
+        $config->setProxyNamespace('DoctrineExtensions\Translatable\Proxies');
+        $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver());
+
+        $conn = array(
+            'driver' => 'pdo_sqlite',
+            'memory' => true,
+        );
+
+        //$config->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
+        
+        $evm = new \Doctrine\Common\EventManager();
+        $this->translationListener = new TranslationListener();
+        $this->translationListener->setTranslatableLocale('en_us');
+        $evm->addEventSubscriber($this->translationListener);
+        $this->em = \Doctrine\ORM\EntityManager::create($conn, $config, $evm);
+
+        $schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->em);
+        $schemaTool->createSchema(array(
+            $this->em->getClassMetadata(self::TEST_ENTITY_CLASS),
+            $this->em->getClassMetadata(self::TRANSLATION_CLASS),
+        ));
+    }
+    
+    public function testStringIdentifier()
+    {
+        $object = new StringIdentifier();
+        $object->setTitle('title in en');
+        $object->setUid(md5(self::TEST_ENTITY_CLASS . time()));
+
+        $this->em->persist($object);
+        $this->em->flush();
+        $this->em->clear();
+        $this->testObjectId = $object->getUid();
+        
+    	$repo = $this->em->getRepository(self::TRANSLATION_CLASS);
+        $object = $this->em->find(self::TEST_ENTITY_CLASS, $this->testObjectId);
+        $this->assertTrue($object instanceof Translatable);
+        
+        $translations = $repo->findTranslations($object);
+        $this->assertEquals(count($translations), 1);
+        $this->assertArrayHasKey('en_us', $translations);
+        
+        $this->assertArrayHasKey('title', $translations['en_us']);
+        $this->assertEquals('title in en', $translations['en_us']['title']);
+
+        $object = $this->em->find(self::TEST_ENTITY_CLASS, $this->testObjectId);
+        $object->setTitle('title in de');
+        $object->setTranslatableLocale('de_de');
+
+        $this->em->persist($object);
+        $this->em->flush();
+        $this->em->clear();
+        
+        $repo = $this->em->getRepository(self::TRANSLATION_CLASS);
+        
+        $translations = $repo->findTranslations($object);
+        $this->assertEquals(count($translations), 2);
+        $this->assertArrayHasKey('de_de', $translations);
+        
+        $this->assertArrayHasKey('title', $translations['de_de']);
+        $this->assertEquals('title in de', $translations['de_de']['title']);
+
+        // dql test object hydration
+        $q = $this->em->createQuery('SELECT si FROM DoctrineExtensions\Translatable\StringIdentifier si WHERE si.uid = :id');
+        $data = $q->execute(
+            array('id' => $this->testObjectId),
+            \Doctrine\ORM\Query::HYDRATE_OBJECT
+        );
+        $this->assertEquals(count($data), 1);
+        $object = $data[0];
+        $this->assertEquals('title in en', $object->getTitle());
+        
+        $this->translationListener->setTranslatableLocale('de_de');
+        $q = $this->em->createQuery('SELECT si FROM DoctrineExtensions\Translatable\StringIdentifier si WHERE si.uid = :id');
+        $data = $q->execute(
+            array('id' => $this->testObjectId),
+            \Doctrine\ORM\Query::HYDRATE_OBJECT
+        );
+        $this->assertEquals(count($data), 1);
+        $object = $data[0];
+        $this->assertEquals('title in de', $object->getTitle());
+    }
+}
+
+/**
+ * @Entity
+ */
+class StringIdentifier implements Translatable
+{
+    /** 
+     * @Id 
+     * @Column(name="uid", type="string", length=32)
+     */
+    private $uid;
+
+    /**
+     * @Column(name="title", type="string", length=128)
+     */
+    private $title;
+    
+    /*
+     * Used locale to override Translation listener`s locale
+     */
+    private $_locale;
+
+    public function getUid()
+    {
+        return $this->uid;
+    }
+    
+    public function setUid($uid)
+    {
+        $this->uid = $uid;
+    }
+    
+    public function setTitle($title)
+    {
+        $this->title = $title;
+    }
+
+    public function getTitle()
+    {
+        return $this->title;
+    }
+    
+    public function getTranslatableFields()
+    {
+        return array('title');
+    }
+    
+    public function setTranslatableLocale($locale)
+    {
+        $this->_locale = $locale;
+    }
+    
+    public function getTranslatableLocale()
+    {
+        return $this->_locale;
+    }
+}

+ 7 - 13
tests/DoctrineExtensions/Translatable/TranslatableTest.php

@@ -49,7 +49,10 @@ class TranslatableTest extends \PHPUnit_Framework_TestCase
             $this->em->getClassMetadata('DoctrineExtensions\Translatable\Comment'),
             $this->em->getClassMetadata('DoctrineExtensions\Translatable\Entity\Translation'),
         ));
-
+    }
+    
+    public function testFixtureGeneratedTranslations()
+    {
         $article = new Article();
         $article->setTitle('title in en');
         $article->setContent('content in en');
@@ -71,10 +74,7 @@ class TranslatableTest extends \PHPUnit_Framework_TestCase
         $this->em->flush();
         $this->articleId = $article->getId();
         $this->em->clear();
-    }
-    
-    public function testFixtureGeneratedTranslations()
-    {
+        
     	$repo = $this->em->getRepository('DoctrineExtensions\Translatable\Entity\Translation');
     	$this->assertTrue($repo instanceof Repository\TranslationRepository);
     	
@@ -109,10 +109,7 @@ class TranslatableTest extends \PHPUnit_Framework_TestCase
 	        $expected = "message{$number} in en";
 	        $this->assertEquals($expected, $translations['en_us']['message']);
         }
-    }
-
-    public function testDefaultLocale()
-    {
+        // test default locale
     	$this->translatableListener->setDefaultLocale('en_us');
     	$article = $this->em->find(
             'DoctrineExtensions\Translatable\Article', 
@@ -150,10 +147,7 @@ class TranslatableTest extends \PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('title', $translations['de_de']);
         $this->assertEquals('title in de', $translations['de_de']['title']);
         $this->translatableListener->setDefaultLocale('');
-    }
-    
-    public function testSecondTranslations()
-    {
+        // test second translations
         $article = $this->em->find(
             'DoctrineExtensions\Translatable\Article', 
             $this->articleId