gediminasm 15 роки тому
батько
коміт
79695dfe54

+ 139 - 0
README.markdown

@@ -0,0 +1,139 @@
+# Some Doctrine 2 Extensions
+
+This package contains several extensions to Doctrine 2 that hook into the facilities of Doctrine and
+offer new functionality or tools to use Doctrine 2 more efficently.
+
+## Including DoctrineExtensions
+
+To include the DoctrineExtensions should fire up an autoloader, for example:
+
+    $classLoader = new \Doctrine\Common\ClassLoader('DoctrineExtensions', "/path/to/extensions");
+    $classLoader->register();
+    
+## Translatable
+
+**Translatable** behavior offers a very handy solution for translating specific record fields
+in diferent languages. Further more, it loads the translations automatically for a locale
+currently used, which can be set to **Translatable Listener** on it`s initialization or later
+for other cases through the entity itself.
+
+This behavior requires an additional metadata path to be specified in order to have a translation
+table and translation entity available. To configure the it correctly you can either 1) add annotation
+driver into driver chain or 2) if you allready are using the annotation driver, simply add the path to
+the Translatable extension Translation entity:
+
+1. Annotation driver mapped into driver chain
+
+    $chainDriverImpl = new Doctrine\ORM\Mapping\Driver\DriverChain();
+    $yourDefaultDriverImpl = new Doctrine\ORM\Mapping\Driver\YamlDriver('/yml/mapping/files');
+    $translatableDriverImpl = $doctrineOrmConfig->newDefaultAnnotationDriver(
+        'path/to/extensions/DoctrineExtensions/Translatable/Entity'
+    );
+    $chainDriverImpl->addDriver($yourDefaultDriverImpl, 'Entities');
+    $chainDriverImpl->addDriver($translatableDriverImpl, 'DoctrineExtensions/Translatable');
+    $doctrineOrmConfig->setMetadataDriverImpl($chainDriverImpl);
+
+2. Another path for Annotation driver:
+
+    $driverImpl = $doctrineOrmConfig->newDefaultAnnotationDriver(array(
+        'default/annotation/entities/path',
+        'path/to/extensions/DoctrineExtensions/Translatable/Entity'
+    ));
+
+To attach the Translatable listener to your event system and to set the translation locale
+to use in global scope for all entities:
+
+    $evm = new Doctrine\Common\EventManager();
+    $translatableListener = new DoctrineExtensions\Translatable\TranslationListener();
+    $translatableListener->setTranslatableLocale('en_us');
+    // in real world app the locale should be loaded from session, example:
+    // Session::getInstance()->read('locale');
+    $evm->addEventSubscriber($translatableListener);
+    // now this event manager should be passed to entity manager constructor
+    
+#### An Usage Example
+
+Article Entity:
+
+    namespace Entities;
+
+    use DoctrineExtensions\Translatable\Translatable;
+    /**
+     * @Table(name="articles")
+     * @Entity
+     */
+    class Article implements Translatable
+    {
+        /**
+         * @Column(name="id", type="integer")
+         * @Id
+         * @GeneratedValue(strategy="IDENTITY")
+         */
+        private $id;
+    
+        /**
+         * @Column(name="title", type="string", length=128)
+         */
+        private $title;
+        
+        /*
+         * Used locale to override Translation listener`s locale
+         */
+        private $_locale;
+    
+        /**
+         * @Column(name="content", type="text")
+         */
+        private $content;
+    
+        public function getId()
+        {
+            return $this->id;
+        }
+    
+        public function setTitle($title)
+        {
+            $this->title = $title;
+        }
+    
+        public function getTitle()
+        {
+            return $this->title;
+        }
+    
+        public function setContent($content)
+        {
+            $this->content = $content;
+        }
+    
+        public function getContent()
+        {
+            return $this->content;
+        }
+        
+        public function getTranslatableFields()
+        {
+            return array('title');
+        }
+        
+        public function setTranslatableLocale($locale)
+        {
+            $this->_locale = $locale;
+        }
+        
+        public function getTranslatableLocale()
+        {
+            return $this->_locale;
+        }
+    }    
+
+To save article with its translations:
+
+    $article = new Entities\Article;
+    $article->setTitle('my title in en');
+    $article->setContent('my content');
+    $em->persist($article);
+    $em->flush();
+    
+**Notice:** current implementation is in alfa version supports only one field translation
+for now. Working on fix to support list of fields

+ 1 - 1
lib/DoctrineExtensions/Translatable/Exception.php

@@ -10,7 +10,7 @@ namespace DoctrineExtensions\Translatable;
  * @link http://www.gediminasm.org
  * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  */
-class TranslatableException extends \Exception
+class Exception extends \Exception
 {
     static public function undefinedLocale()
     {

+ 17 - 14
lib/DoctrineExtensions/Translatable/TranslationListener.php

@@ -37,7 +37,7 @@ class TranslationListener implements EventSubscriber
 	 *  
 	 * @var string
 	 */
-	protected $_locale = 'en-us';
+	protected $_locale = 'en_us';
 	
 	/**
 	 * List of translations which do not have the foreign
@@ -125,13 +125,15 @@ class TranslationListener implements EventSubscriber
         if ($entity instanceof Translatable && count($this->_pendingTranslations)) {
         	$oid = spl_object_hash($entity);
         	if (array_key_exists($oid, $this->_pendingTranslations)) {
-                // load the pending translation without key
-        		$translation = $this->_pendingTranslations[$oid];
-                // schedule an extra update for the foreign key
-                $uow = $em->getUnitOfWork();
-                $uow->scheduleExtraUpdate($translation, array(
-                    'foreignKey' => array(null, $entity->getId())
-                ));
+                // load the pending translations without key
+        		$translations = $this->_pendingTranslations[$oid];
+        		foreach ($translations as $translation) {
+	                // schedule an extra update for the foreign key
+	                $uow = $em->getUnitOfWork();
+	                $uow->scheduleExtraUpdate($translation, array(
+	                    'foreignKey' => array(null, $entity->getId())
+	                ));
+        		}
             }
         }
     }
@@ -148,7 +150,7 @@ class TranslationListener implements EventSubscriber
     {
     	$em = $args->getEntityManager();
     	$entity = $args->getEntity();
-    	
+
     	$entityClass = get_class($entity);
     	if ($entity instanceof Translatable && count($entity->getTranslatableFields())) {
             $locale = strtolower($this->getTranslatableLocale($entity));
@@ -196,12 +198,12 @@ class TranslationListener implements EventSubscriber
         } elseif ($isInsert) {
             $entityId = null;
         } else {
-            throw TranslatableException::singleIdentifierRequired($entityClass);
+            throw Exception::singleIdentifierRequired($entityClass);
         }
         
         // @todo: add support for string type identifier also 
-        if (!is_int($entityId)) {
-        	throw TranslatableException::invalidIdentifierType($entityId);
+        if (!is_int($entityId) && !is_null($entityId)) {
+        	throw Exception::invalidIdentifierType($entityId);
         }
         
         // load the currently used locale
@@ -240,7 +242,7 @@ class TranslationListener implements EventSubscriber
             // if we do not have the primary key yet available
             // keep this translation in memory for later update
             if ($isInsert && is_null($entityId)) {
-            	$this->_pendingTranslations[spl_object_hash($entity)] = $translation;
+            	$this->_pendingTranslations[spl_object_hash($entity)][$field] = $translation;
             }
         }
     }
@@ -273,6 +275,7 @@ class TranslationListener implements EventSubscriber
             compact('field', 'locale', 'entityId', 'entityClass'),
             $contentOnly ? Query::HYDRATE_ARRAY : Query::HYDRATE_OBJECT
         );
+        
         if ($result && is_array($result) && count($result)) {
             $result = array_shift($result);
             if ($contentOnly) {
@@ -293,7 +296,7 @@ class TranslationListener implements EventSubscriber
     protected function _validateLocale($locale)
     {
     	if (!strlen($locale)) {
-    		throw TranslatableException::undefinedLocale();
+    		throw Exception::undefinedLocale();
     	}
     }
 }