From 81514767330333fdcfac3dd347718d3a585ea91f Mon Sep 17 00:00:00 2001 From: mikl <> Date: Mon, 30 Jun 2008 17:04:42 +0000 Subject: Implemented MessageSource_Database --- .gitattributes | 1 + HISTORY | 1 + UPGRADE | 6 + framework/Exceptions/messages/messages.txt | 5 +- framework/I18N/TGlobalization.php | 8 +- framework/I18N/core/MessageSource.php | 20 +- framework/I18N/core/MessageSource_Database.php | 322 +++++++++++++++++++++++++ 7 files changed, 350 insertions(+), 13 deletions(-) create mode 100644 framework/I18N/core/MessageSource_Database.php 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: + + 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: * - * $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 @@ +_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 append() 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; + } + +} +?> -- cgit v1.2.3