* @version $Id: sfMessageSource_MySQL.class.php 4340 2007-06-23 06:47:05Z fabien $ * @package symfony * @subpackage i18n */ /** * Get the I18N utility file, contains the DSN parser. */ require_once(dirname(__FILE__).'/util.php'); /** * sfMessageSource_MySQL class. * * Retrieve the message translation from a MySQL database. * * See the MessageSource::factory() method to instantiate this class. * * MySQL schema: * * CREATE TABLE `catalogue` ( * `cat_id` int(11) NOT NULL auto_increment, * `name` varchar(100) NOT NULL default '', * `source_lang` varchar(100) NOT NULL default '', * `target_lang` varchar(100) NOT NULL default '', * `date_created` int(11) NOT NULL default '0', * `date_modified` int(11) NOT NULL default '0', * `author` varchar(255) NOT NULL default '', * PRIMARY KEY (`cat_id`) * ) TYPE=InnoDB; * * CREATE TABLE `trans_unit` ( * `msg_id` int(11) NOT NULL auto_increment, * `cat_id` int(11) NOT NULL default '1', * `id` varchar(255) NOT NULL default '', * `source` text NOT NULL, * `target` text NOT NULL, * `comments` text NOT NULL, * `date_added` int(11) NOT NULL default '0', * `date_modified` int(11) NOT NULL default '0', * `author` varchar(255) NOT NULL default '', * `translated` tinyint(1) NOT NULL default '0', * PRIMARY KEY (`msg_id`) * ) TYPE=InnoDB; * * Propel schema (in .xml format): * * * ... * * * * * * * * *
* * * * * * * * * * * * * * * *
* ... *
* * @author Xiang Wei Zhuo * @version v1.0, last update on Fri Dec 24 16:58:58 EST 2004 * @package System.I18N.core */ class sfMessageSource_MySQL extends sfMessageSource { /** * The datasource string, full DSN to the database. * @var string */ protected $source; /** * The DSN array property, parsed by PEAR's DB DSN parser. * @var array */ protected $dsn; /** * A resource link to the database * @var db */ protected $db; /** * Constructor. * Creates a new message source using MySQL. * * @param string MySQL datasource, in PEAR's DB DSN format. * @see MessageSource::factory(); */ function __construct($source) { $this->source = (string) $source; $this->dsn = parseDSN($this->source); $this->db = $this->connect(); } /** * Destructor, closes the database connection. */ function __destruct() { @mysql_close($this->db); } /** * Connects to the MySQL datasource * * @return resource MySQL connection. * @throws sfException, connection and database errors. */ protected function connect() { $dsninfo = $this->dsn; if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix') { $dbhost = ':'.$dsninfo['socket']; } else { $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost'; if (!empty($dsninfo['port'])) { $dbhost = ':' . $dsninfo['socket']; } } $user = $dsninfo['username']; $pw = $dsninfo['password']; $connect_function = 'mysql_connect'; if ($dbhost && $user && $pw) { $conn = @$connect_function($dbhost, $user, $pw); } elseif ($dbhost && $user) { $conn = @$connect_function($dbhost, $user); } elseif ($dbhost) { $conn = @$connect_function($dbhost); } else { $conn = false; } if (empty($conn)) { throw new sfException(sprintf('Error in connecting to %s.', $dsninfo)); } if ($dsninfo['database']) { if (!@mysql_select_db($dsninfo['database'], $conn)) { throw new sfException(sprintf('Error in connecting database, dsn: %s.', $dsninfo)); } } else { throw new sfException('Please provide a database for message translation.'); } return $conn; } /** * Gets the database connection. * * @return db database connection. */ public function connection() { return $this->db; } /** * Gets 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) { $variant = mysql_real_escape_string($variant, $this->db); $statement = "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"; $rs = mysql_query($statement, $this->db); $result = array(); while ($row = mysql_fetch_array($rs, MYSQL_NUM)) { $source = $row[1]; $result[$source][] = $row[2]; //target $result[$source][] = $row[0]; //id $result[$source][] = $row[3]; //comments } return $result; } /** * Gets 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) { $source = mysql_real_escape_string($source, $this->db); $rs = mysql_query("SELECT date_modified FROM catalogue WHERE name = '{$source}'", $this->db); $result = $rs ? intval(mysql_result($rs, 0)) : 0; return $result; } /** * Checks 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) { $variant = mysql_real_escape_string ($variant, $this->db); $rs = mysql_query("SELECT COUNT(*) FROM catalogue WHERE name = '{$variant}'", $this->db); $row = mysql_fetch_array($rs, MYSQL_NUM); $result = $row && $row[0] == '1'; return $result; } /** * Gets 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, $max = count($variants); $i < $max; $i++) { if (strlen($variants[$i]) > 0) { $variant .= $variant ? '_'.$variants[$i] : $variants[$i]; $catalogues[] = $catalogue.'.'.$variant; } } return array_reverse($catalogues); } /** * Retrieves catalogue details, array($cat_id, $variant, $count). * * @param string catalogue * @return array catalogue details, array($cat_id, $variant, $count). */ protected function getCatalogueDetails($catalogue = 'messages') { if (empty($catalogue)) { $catalogue = 'messages'; } $variant = $catalogue.'.'.$this->culture; $name = mysql_real_escape_string($this->getSource($variant), $this->db); $rs = mysql_query("SELECT cat_id FROM catalogue WHERE name = '{$name}'", $this->db); if (mysql_num_rows($rs) != 1) { return false; } $cat_id = intval(mysql_result($rs, 0)); // first get the catalogue ID $rs = mysql_query("SELECT COUNT(*) FROM trans_unit WHERE cat_id = {$cat_id}", $this->db); $count = intval(mysql_result($rs, 0)); return array($cat_id, $variant, $count); } /** * Updates the catalogue last modified time. * * @return boolean true if updated, false otherwise. */ protected function updateCatalogueTime($cat_id, $variant) { $time = time(); $result = mysql_query("UPDATE catalogue SET date_modified = {$time} WHERE cat_id = {$cat_id}", $this->db); if (!empty($this->cache)) { $this->cache->clean($variant, $this->culture); } return $result; } /** * Saves 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(); foreach ($messages as $message) { $count++; $inserted++; $message = mysql_real_escape_string($message, $this->db); $statement = "INSERT INTO trans_unit (cat_id,id,source,date_added) VALUES ({$cat_id}, {$count},'{$message}',$time)"; mysql_query($statement, $this->db); } if ($inserted > 0) { $this->updateCatalogueTime($cat_id, $variant); } return $inserted > 0; } /** * Deletes 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; } $text = mysql_real_escape_string($message, $this->db); $statement = "DELETE FROM trans_unit WHERE cat_id = {$cat_id} AND source = '{$message}'"; $deleted = false; mysql_query($statement, $this->db); if (mysql_affected_rows($this->db) == 1) { $deleted = $this->updateCatalogueTime($cat_id, $variant); } return $deleted; } /** * Updates 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; } $comments = mysql_real_escape_string($comments, $this->db); $target = mysql_real_escape_string($target, $this->db); $text = mysql_real_escape_string($text, $this->db); $time = time(); $statement = "UPDATE trans_unit SET target = '{$target}', comments = '{$comments}', date_modified = '{$time}' WHERE cat_id = {$cat_id} AND source = '{$text}'"; $updated = false; mysql_query($statement, $this->db); if (mysql_affected_rows($this->db) == 1) { $updated = $this->updateCatalogueTime($cat_id, $variant); } return $updated; } /** * Returns a list of catalogue as key and all it variants as value. * * @return array list of catalogues */ function catalogues() { $statement = 'SELECT name FROM catalogue ORDER BY name'; $rs = mysql_query($statement, $this->db); $result = array(); while($row = mysql_fetch_array($rs, MYSQL_NUM)) { $details = explode('.', $row[0]); if (!isset($details[1])) { $details[1] = null; } $result[] = $details; } return $result; } }