summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormikl <>2008-06-30 17:04:42 +0000
committermikl <>2008-06-30 17:04:42 +0000
commit81514767330333fdcfac3dd347718d3a585ea91f (patch)
tree793a3008a569549d185f2708cb23de997dcc3571
parent4fdb3675a79f80e8d9400aad7015250d125c92dd (diff)
Implemented MessageSource_Database
-rw-r--r--.gitattributes1
-rw-r--r--HISTORY1
-rw-r--r--UPGRADE6
-rw-r--r--framework/Exceptions/messages/messages.txt5
-rw-r--r--framework/I18N/TGlobalization.php8
-rw-r--r--framework/I18N/core/MessageSource.php20
-rw-r--r--framework/I18N/core/MessageSource_Database.php322
7 files changed, 350 insertions, 13 deletions
diff --git a/.gitattributes b/.gitattributes
index 291182a4..e7a3d8b6 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2225,6 +2225,7 @@ framework/I18N/core/IMessageSource.php -text
framework/I18N/core/MessageCache.php -text
framework/I18N/core/MessageFormat.php -text
framework/I18N/core/MessageSource.php -text
+framework/I18N/core/MessageSource_Database.php -text
framework/I18N/core/MessageSource_MySQL.php -text
framework/I18N/core/MessageSource_SQLite.php -text
framework/I18N/core/MessageSource_XLIFF.php -text
diff --git a/HISTORY b/HISTORY
index be5dc92a..8cf33f37 100644
--- a/HISTORY
+++ b/HISTORY
@@ -10,6 +10,7 @@ BUG: Ticket#860 - Prado::localize() bug (japplegame)
BUG: Ticket#870 - Callback with redirect breaks lifecycle of page (stever)
BUG: Ticket#872 - use PATH_SEPARATOR in phpunit.php (fragmaster b)
ENH: Added Prado.Validation.validateControl(id) on client side to validate a specific control (Michael)
+ENH: Added MessageSource_Database to I18N (uses TDbConnection) (Michael)
Version 3.1.2 April 21, 2008
============================
diff --git a/UPGRADE b/UPGRADE
index 89399c05..69fab95e 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -11,6 +11,12 @@ for both A and B.
Upgrading from v3.1.2
---------------------
+- The Translation configuration now also accepts type 'Database' to
+ ease the setup of DB base translation. A valid ConnectionID has to
+ be supplied in the source parameter:
+ <translation type="Database" source="db1" autosave="true" cache="false" />
+ Type 'MySQL' can still be used but is deprecated and might be removed
+ in a later release.
Upgrading from v3.1.1
diff --git a/framework/Exceptions/messages/messages.txt b/framework/Exceptions/messages/messages.txt
index 36a23701..3edd5d49 100644
--- a/framework/Exceptions/messages/messages.txt
+++ b/framework/Exceptions/messages/messages.txt
@@ -349,6 +349,9 @@ clientscript_invalid_package_path = Invalid PackagePath '{0}' for TClientScript
tdatepicker_autopostback_unsupported = '{0}' does not support AutoPostBack.
globalization_cache_path_failed = Unable to create translation message cache path '{0}'. Make sure the parent directory exists and is writable by the Web process.
globalization_source_path_failed = Unable to create translation message path '{0}'. Make sure the parent directory exists and is writable by the Web process.
+messagesource_connectionid_invalid = MessageSource_Database.source '{0}' does not point to a valid TDataSourceConfig module.
+messagesource_connectionid_required = ConnectionID in MessageSource_Database.source is required.
+
callback_not_support_no_priority_state_update = Callback request does not support unprioritized pagestate update.
callback_invalid_callback_options = '{1}' is not a valid TCallbackOptions control for Callback control '{0}'.
callback_invalid_clientside_options = Callback ClientSide property must be either a string that is the ID of a TCallbackOptions control or an instance of TCallbackClientSideOptions.=======
@@ -462,4 +465,4 @@ ar_delete_invalid = The {0} instance cannot be deleted because it is either
datasource_dbconnection_invalid = TDataSourceConfig.DbConnection '{0}' is invalid. Please make sure it points to a valid application module.
response_status_reason_missing = HTTP 1.1 need reason for extended status-codes
-response_status_reason_badchars = For HTTP 1.1 header, the token status-reason must not contain token CR or LF \ No newline at end of file
+response_status_reason_badchars = For HTTP 1.1 header, the token status-reason must not contain token CR or LF
diff --git a/framework/I18N/TGlobalization.php b/framework/I18N/TGlobalization.php
index 471869c7..a30c8423 100644
--- a/framework/I18N/TGlobalization.php
+++ b/framework/I18N/TGlobalization.php
@@ -155,8 +155,10 @@ class TGlobalization extends TModule
/**
* Sets the translation configuration. Example configuration:
* <code>
- * $config['type'] = 'XLIFF'; //XLIFF, gettext, mysql or sqlite
- * $config['source'] = 'Path.to.directory'; //or database connection string
+ * $config['type'] = 'XLIFF'; //XLIFF, gettext, Database or MySQL (deprecated)
+ * $config['source'] = 'Path.to.directory'; // for types XLIFF and gettext
+ * $config['source'] = 'connectionId'; // for type Database
+ * $config['source'] = 'mysql://user:pw@host/db'; // for type MySQL (deprecated)
* $config['catalogue'] = 'messages'; //default catalog
* $config['autosave'] = 'true'; //save untranslated message
* $config['cache'] = 'true'; //cache translated message
@@ -266,4 +268,4 @@ class TGlobalization extends TModule
}
-?> \ No newline at end of file
+?>
diff --git a/framework/I18N/core/MessageSource.php b/framework/I18N/core/MessageSource.php
index 6563f8c9..68fcd903 100644
--- a/framework/I18N/core/MessageSource.php
+++ b/framework/I18N/core/MessageSource.php
@@ -108,26 +108,28 @@ abstract class MessageSource implements IMessageSource
/**
* Factory method to instantiate a new MessageSource depending on the
- * source type. The allowed source types are 'XLIFF', 'SQLite',
- * 'MySQL', and 'gettext'. The source parameter is dependent on the
- * source type. For 'gettext' and 'XLIFF', it should point to the directory
- * where the messages are stored. For database types, e.g. 'SQLite' and
- * 'MySQL', it should be a PEAR DB style DSN string.
+ * source type. The allowed source types are 'XLIFF', 'gettext' and
+ * 'Database'. The source parameter depends on the source type.
+ * For 'gettext' and 'XLIFF', 'source' should point to the directory
+ * where the messages are stored.
+ * For 'Database', 'source' should be a valid connection id.
+ * If (deprecated) 'MySQL' is used, 'source' must contain a valid
+ * DSN.
*
* Custom message source are possible by supplying the a filename parameter
* in the factory method.
*
* @param string the message source type.
- * @param string the location of the resource.
+ * @param string the location of the resource or the ConnectionID.
* @param string the filename of the custom message source.
* @return MessageSource a new message source of the specified type.
* @throws InvalidMessageSourceTypeException
*/
static function &factory($type, $source='.', $filename='')
{
- $types = array('XLIFF', 'SQLite', 'MySQL', 'gettext');
+ $types = array('XLIFF', 'MySQL', 'Database', 'gettext');
- if(empty($filename) && in_array($type, $types) == false)
+ if(empty($filename) && !in_array($type, $types))
throw new Exception('Invalid type "'.$type.'", valid types are '.
implode(', ', $types));
@@ -330,4 +332,4 @@ class TMessageSourceIOException extends TException
{
}
-?> \ No newline at end of file
+?>
diff --git a/framework/I18N/core/MessageSource_Database.php b/framework/I18N/core/MessageSource_Database.php
new file mode 100644
index 00000000..4d756820
--- /dev/null
+++ b/framework/I18N/core/MessageSource_Database.php
@@ -0,0 +1,322 @@
+<?php
+/**
+ * MessageSource_MySQL class file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD License.
+ *
+ * Copyright(c) 2004 by Qiang Xue. All rights reserved.
+ *
+ * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
+ * The latest version of PRADO can be obtained from:
+ * {@link http://prado.sourceforge.net/}
+ *
+ * @package System.I18N.core
+ */
+
+/**
+ * Get the MessageSource class file.
+ */
+require_once(dirname(__FILE__).'/MessageSource.php');
+
+/**
+ * MessageSource_MySQL class.
+ *
+ * Retrive the message translation from a MySQL database.
+ *
+ * See the MessageSource::factory() method to instantiate this class.
+ *
+ * @package System.I18N.core
+ */
+class MessageSource_Database extends MessageSource
+{
+ private $_connID='';
+ private $_conn;
+
+ /**
+ * Constructor.
+ * Create a new message source using a Database
+ * @param string MySQL datasource, in PEAR's DB DSN format.
+ * @see MessageSource::factory();
+ */
+ function __construct($source)
+ {
+ $this->_connID= (string)$source;
+ }
+
+ /**
+ * @return TDbConnection the database connection that may be used to retrieve messages.
+ */
+ public function getDbConnection()
+ {
+ if($this->_conn===null)
+ {
+ $this->_conn=$this->createDbConnection($this->_connID);
+ $this->_conn->setActive(true);
+ }
+ return $this->_conn;
+ }
+
+ /**
+ * Creates the DB connection.
+ * @param string the module ID for TDataSourceConfig
+ * @return TDbConnection the created DB connection
+ * @throws TConfigurationException if module ID is invalid or empty
+ */
+ protected function createDbConnection($connectionID)
+ {
+ if($connectionID!=='')
+ {
+ $conn=Prado::getApplication()->getModule($connectionID);
+ if($conn instanceof TDataSourceConfig)
+ return $conn->getDbConnection();
+ else
+ throw new TConfigurationException('messagesource_connectionid_invalid',$connectionID);
+ }
+ else
+ throw new TConfigurationException('messagesource_connectionid_required');
+ }
+
+ /**
+ * Get an array of messages for a particular catalogue and cultural
+ * variant.
+ * @param string the catalogue name + variant
+ * @return array translation messages.
+ */
+ protected function &loadData($variant)
+ {
+ $command=$this->getDBConnection()->createCommand(
+ 'SELECT t.id, t.source, t.target, t.comments
+ FROM trans_unit t, catalogue c
+ WHERE c.cat_id = t.cat_id
+ AND c.name = :variant
+ ORDER BY id ASC');
+ $command->bindParameter(':variant',$variant,PDO::PARAM_STR);
+ $dataReader=$command->query();
+
+ $result = array();
+
+ foreach ($dataReader as $row)
+ $result[$row['source']] = array($row['target'],$row['id'],$row['comments']);
+
+ return $result;
+ }
+
+ /**
+ * Get the last modified unix-time for this particular catalogue+variant.
+ * We need to query the database to get the date_modified.
+ * @param string catalogue+variant
+ * @return int last modified in unix-time format.
+ */
+ protected function getLastModified($source)
+ {
+ $command=$this->getDBConnection()->createCommand(
+ 'SELECT date_modified FROM catalogue WHERE name = :source');
+ $command->bindParameter(':source',$source,PDO::PARAM_STR);
+ $result=$command->queryScalar();
+ return $result ? $result : 0;
+ }
+
+
+ /**
+ * Check if a particular catalogue+variant exists in the database.
+ * @param string catalogue+variant
+ * @return boolean true if the catalogue+variant is in the database,
+ * false otherwise.
+ */
+ protected function isValidSource($variant)
+ {
+ $command=$this->getDBConnection()->createCommand(
+ 'SELECT COUNT(*) FROM catalogue WHERE name = :variant');
+ $command->bindParameter(':variant',$variant,PDO::PARAM_STR);
+ return $command->queryScalar()==1;
+ }
+
+ /**
+ * Get all the variants of a particular catalogue.
+ * @param string catalogue name
+ * @return array list of all variants for this catalogue.
+ */
+ protected function getCatalogueList($catalogue)
+ {
+ $variants = explode('_',$this->culture);
+
+ $catalogues = array($catalogue);
+
+ $variant = null;
+
+ for($i = 0, $k = count($variants); $i < $k; ++$i)
+ {
+ if(isset($variants[$i]{0}))
+ {
+ $variant .= ($variant)?'_'.$variants[$i]:$variants[$i];
+ $catalogues[] = $catalogue.'.'.$variant;
+ }
+ }
+ return array_reverse($catalogues);
+ }
+
+ /**
+ * Retrive catalogue details, array($cat_id, $variant, $count).
+ * @param string catalogue
+ * @return array catalogue details, array($cat_id, $variant, $count).
+ */
+ private function getCatalogueDetails($catalogue='messages')
+ {
+ if(empty($catalogue))
+ $catalogue = 'messages';
+
+ $variant = $catalogue.'.'.$this->culture;
+
+ $command=$this->getDBConnection()->createCommand(
+ 'SELECT cat_id FROM catalogue WHERE name = :variant');
+ $command->bindParameter(':variant',$variant,PDO::PARAM_STR);
+ $cat_id=$command->queryScalar();
+
+ if ($cat_id===null) return false;
+
+ $command=$this->getDBConnection()->createCommand(
+ 'SELECT COUNT(msg_id) FROM trans_unit WHERE cat_id = :catid ');
+ $command->bindParameter(':catid',$cat_id,PDO::PARAM_INT);
+ $count=$command->queryScalar();
+
+ return array($cat_id, $variant, $count);
+ }
+
+ /**
+ * Update the catalogue last modified time.
+ * @return boolean true if updated, false otherwise.
+ */
+ private function updateCatalogueTime($cat_id, $variant)
+ {
+ $time = time();
+ $command=$this->getDBConnection()->createCommand(
+ 'UPDATE catalogue SET date_modified = :moddate WHERE cat_id = :catid');
+ $command->bindParameter(':moddate',$time,PDO::PARAM_INT);
+ $command->bindParameter(':catid',$cat_id,PDO::PARAM_INT);
+ $command->execute();
+
+ if(!empty($this->cache))
+ $this->cache->clean($variant, $this->culture);
+
+ return $result;
+ }
+
+ /**
+ * Save the list of untranslated blocks to the translation source.
+ * If the translation was not found, you should add those
+ * strings to the translation source via the <b>append()</b> method.
+ * @param string the catalogue to add to
+ * @return boolean true if saved successfuly, false otherwise.
+ */
+ function save($catalogue='messages')
+ {
+ $messages = $this->untranslated;
+
+ if(count($messages) <= 0) return false;
+
+ $details = $this->getCatalogueDetails($catalogue);
+
+ if($details)
+ list($cat_id, $variant, $count) = $details;
+ else
+ return false;
+
+ if($cat_id <= 0) return false;
+ $inserted = 0;
+
+ $time = time();
+
+ $command=$this->getDBConnection()->createCommand(
+ 'INSERT INTO trans_unit (cat_id,id,source,date_added) VALUES (:catid,:id,:source,:dateadded)');
+ $command->bindParameter(':catid',$cat_id,PDO::PARAM_INT);
+ $command->bindParameter(':id',$count,PDO::PARAM_INT);
+ $command->bindParameter(':source',$message,PDO::PARAM_STR);
+ $command->bindParameter(':dateadded',$time,PDO::PARAM_INT);
+ foreach($messages as $message)
+ {
+ $count++; $inserted++;
+ $command->execute();
+ }
+ if($inserted > 0)
+ $this->updateCatalogueTime($cat_id, $variant);
+
+ return $inserted > 0;
+ }
+
+ /**
+ * Delete a particular message from the specified catalogue.
+ * @param string the source message to delete.
+ * @param string the catalogue to delete from.
+ * @return boolean true if deleted, false otherwise.
+ */
+ function delete($message, $catalogue='messages')
+ {
+ $details = $this->getCatalogueDetails($catalogue);
+ if($details)
+ list($cat_id, $variant, $count) = $details;
+ else
+ return false;
+
+ $command=$this->getDBConnection()->createCommand(
+ 'DELETE FROM trans_unit WHERE cat_id = :catid AND source = :message');
+ $command->bindParameter(':catid',$cat_id,PDO::PARAM_INT);
+ $command->bindParameter(':message',$message,PDO::PARAM_STR);
+
+ return ($command->execute()==1) ? $this->updateCatalogueTime($cat_id, $variant) : false;
+
+ }
+
+ /**
+ * Update the translation.
+ * @param string the source string.
+ * @param string the new translation string.
+ * @param string comments
+ * @param string the catalogue of the translation.
+ * @return boolean true if translation was updated, false otherwise.
+ */
+ function update($text, $target, $comments, $catalogue='messages')
+ {
+ $details = $this->getCatalogueDetails($catalogue);
+ if($details)
+ list($cat_id, $variant, $count) = $details;
+ else
+ return false;
+
+ $time = time();
+ $command=$this->getDBConnection()->createCommand(
+ 'UPDATE trans_unit SET target = :target, comments = :comments, date_modified = :datemod
+ WHERE cat_id = :catid AND source = :source');
+ $command->bindParameter(':target',$target,PDO::PARAM_STR);
+ $command->bindParameter(':comments',$comments,PDO::PARAM_STR);
+ $command->bindParameter(':datemod',$time,PDO::PARAM_INT);
+ $command->bindParameter(':catid',$cat_id,PDO::PARAM_INT);
+ $command->bindParameter(':source',$text,PDO::PARAM_STR);
+
+ return ($command->execute()==1) ? $this->updateCatalogueTime($cat_id, $variant) : false;
+ }
+
+ /**
+ * Returns a list of catalogue as key and all it variants as value.
+ * @return array list of catalogues
+ */
+ function catalogues()
+ {
+ $command=$this->getDBConnection()->createCommand( 'SELECT name FROM catalogue ORDER BY name');
+ $dataReader=$command->query();
+
+ $result = array();
+
+ foreach ($dataReader as $row)
+ {
+ $details = explode('.',$row[0]);
+ if(!isset($details[1])) $details[1] = null;
+
+ $result[] = $details;
+ }
+
+ return $result;
+ }
+
+}
+?>