1. sfMessageSource_MySQL.class.php
  2. /** * 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 symfony * @subpackage i18n */
  3. class sfMessageSource_MySQL extends sfMessageSource_Database
  4. {
  5. /**
  6. * The datasource string, full DSN to the database.
  7. * @var string
  8. */
  9. protected $source;
  10. /**
  11. * The DSN array property, parsed by PEAR's DB DSN parser.
  12. * @var array
  13. */
  14. protected $dsn;
  15. /**
  16. * A resource link to the database
  17. * @var db
  18. */
  19. protected $db;
  20. /**
  21. * Constructor.
  22. * Creates a new message source using MySQL.
  23. *
  24. * @param string $source MySQL datasource, in PEAR's DB DSN format.
  25. * @see MessageSource::factory();
  26. */
  27. function __construct($source)
  28. {
  29. $this->source = (string) $source;
  30. $this->dsn = $this->parseDSN($this->source);
  31. $this->db = $this->connect();
  32. }
  33. /**
  34. * Destructor, closes the database connection.
  35. */
  36. function __destruct()
  37. {
  38. @mysql_close($this->db);
  39. }
  40. /**
  41. * Connects to the MySQL datasource
  42. *
  43. * @return resource MySQL connection.
  44. * @throws sfException, connection and database errors.
  45. */
  46. protected function connect()
  47. {
  48. $dsninfo = $this->dsn;
  49. if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix')
  50. {
  51. $dbhost = ':'.$dsninfo['socket'];
  52. }
  53. else
  54. {
  55. $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  56. if (!empty($dsninfo['port']))
  57. {
  58. $dbhost .= ':'.$dsninfo['port'];
  59. }
  60. }
  61. $user = $dsninfo['username'];
  62. $pw = $dsninfo['password'];
  63. $connect_function = 'mysql_connect';
  64. if (!function_exists($connect_function))
  65. {
  66. throw new RuntimeException('The function mysql_connect() does not exist. Please confirm MySQL is enabled in php.ini');
  67. }
  68. if ($dbhost && $user && $pw)
  69. {
  70. $conn = @$connect_function($dbhost, $user, $pw);
  71. }
  72. elseif ($dbhost && $user)
  73. {
  74. $conn = @$connect_function($dbhost, $user);
  75. }
  76. elseif ($dbhost)
  77. {
  78. $conn = @$connect_function($dbhost);
  79. }
  80. else
  81. {
  82. $conn = false;
  83. }
  84. if (empty($conn))
  85. {
  86. throw new sfException(sprintf('Error in connecting to %s.', $dsninfo));
  87. }
  88. if ($dsninfo['database'])
  89. {
  90. if (!@mysql_select_db($dsninfo['database'], $conn))
  91. {
  92. throw new sfException(sprintf('Error in connecting database, dsn: %s.', $dsninfo));
  93. }
  94. }
  95. else
  96. {
  97. throw new sfException('Please provide a database for message translation.');
  98. }
  99. return $conn;
  100. }
  101. /**
  102. * Gets the database connection.
  103. *
  104. * @return db database connection.
  105. */
  106. public function connection()
  107. {
  108. return $this->db;
  109. }
  110. /**
  111. * Gets an array of messages for a particular catalogue and cultural variant.
  112. *
  113. * @param string $variant the catalogue name + variant
  114. * @return array translation messages.
  115. */
  116. public function &loadData($variant)
  117. {
  118. $variant = mysql_real_escape_string($variant, $this->db);
  119. $statement =
  120. "SELECT t.id, t.source, t.target, t.comments
  121. FROM trans_unit t, catalogue c
  122. WHERE c.cat_id = t.cat_id
  123. AND c.name = '{$variant}'
  124. ORDER BY id ASC";
  125. $rs = mysql_query($statement, $this->db);
  126. $result = array();
  127. while ($row = mysql_fetch_array($rs, MYSQL_NUM))
  128. {
  129. $source = $row[1];
  130. $result[$source][] = $row[2]; //target
  131. $result[$source][] = $row[0]; //id
  132. $result[$source][] = $row[3]; //comments
  133. }
  134. return $result;
  135. }
  136. /**
  137. * Gets the last modified unix-time for this particular catalogue+variant.
  138. * We need to query the database to get the date_modified.
  139. *
  140. * @param string $source catalogue+variant
  141. * @return int last modified in unix-time format.
  142. */
  143. protected function getLastModified($source)
  144. {
  145. $source = mysql_real_escape_string($source, $this->db);
  146. $rs = mysql_query("SELECT date_modified FROM catalogue WHERE name = '{$source}'", $this->db);
  147. $result = $rs ? intval(mysql_result($rs, 0)) : 0;
  148. return $result;
  149. }
  150. /**
  151. * Checks if a particular catalogue+variant exists in the database.
  152. *
  153. * @param string $variant catalogue+variant
  154. * @return boolean true if the catalogue+variant is in the database, false otherwise.
  155. */
  156. public function isValidSource($variant)
  157. {
  158. $variant = mysql_real_escape_string ($variant, $this->db);
  159. $rs = mysql_query("SELECT COUNT(*) FROM catalogue WHERE name = '{$variant}'", $this->db);
  160. $row = mysql_fetch_array($rs, MYSQL_NUM);
  161. $result = $row && $row[0] == '1';
  162. return $result;
  163. }
  164. /**
  165. * Retrieves catalogue details, array($cat_id, $variant, $count).
  166. *
  167. * @param string $catalogue catalogue
  168. * @return array catalogue details, array($cat_id, $variant, $count).
  169. */
  170. protected function getCatalogueDetails($catalogue = 'messages')
  171. {
  172. if (empty($catalogue))
  173. {
  174. $catalogue = 'messages';
  175. }
  176. $variant = $catalogue.'.'.$this->culture;
  177. $name = mysql_real_escape_string($this->getSource($variant), $this->db);
  178. $rs = mysql_query("SELECT cat_id FROM catalogue WHERE name = '{$name}'", $this->db);
  179. if (mysql_num_rows($rs) != 1)
  180. {
  181. return false;
  182. }
  183. $cat_id = intval(mysql_result($rs, 0));
  184. // first get the catalogue ID
  185. $rs = mysql_query("SELECT COUNT(*) FROM trans_unit WHERE cat_id = {$cat_id}", $this->db);
  186. $count = intval(mysql_result($rs, 0));
  187. return array($cat_id, $variant, $count);
  188. }
  189. /**
  190. * Updates the catalogue last modified time.
  191. *
  192. * @return boolean true if updated, false otherwise.
  193. */
  194. protected function updateCatalogueTime($cat_id, $variant)
  195. {
  196. $time = time();
  197. $result = mysql_query("UPDATE catalogue SET date_modified = {$time} WHERE cat_id = {$cat_id}", $this->db);
  198. if ($this->cache)
  199. {
  200. $this->cache->remove($variant.':'.$this->culture);
  201. }
  202. return $result;
  203. }
  204. /**
  205. * Saves the list of untranslated blocks to the translation source.
  206. * If the translation was not found, you should add those
  207. * strings to the translation source via the <b>append()</b> method.
  208. *
  209. * @param string $catalogue the catalogue to add to
  210. * @return boolean true if saved successfuly, false otherwise.
  211. */
  212. function save($catalogue = 'messages')
  213. {
  214. $messages = $this->untranslated;
  215. if (count($messages) <= 0)
  216. {
  217. return false;
  218. }
  219. $details = $this->getCatalogueDetails($catalogue);
  220. if ($details)
  221. {
  222. list($cat_id, $variant, $count) = $details;
  223. }
  224. else
  225. {
  226. return false;
  227. }
  228. if ($cat_id <= 0)
  229. {
  230. return false;
  231. }
  232. $inserted = 0;
  233. $time = time();
  234. foreach ($messages as $message)
  235. {
  236. $count++;
  237. $inserted++;
  238. $message = mysql_real_escape_string($message, $this->db);
  239. $statement = "INSERT INTO trans_unit
  240. (cat_id,id,source,date_added) VALUES
  241. ({$cat_id}, {$count},'{$message}',$time)";
  242. mysql_query($statement, $this->db);
  243. }
  244. if ($inserted > 0)
  245. {
  246. $this->updateCatalogueTime($cat_id, $variant);
  247. }
  248. return $inserted > 0;
  249. }
  250. /**
  251. * Deletes a particular message from the specified catalogue.
  252. *
  253. * @param string $message the source message to delete.
  254. * @param string $catalogue the catalogue to delete from.
  255. * @return boolean true if deleted, false otherwise.
  256. */
  257. function delete($message, $catalogue = 'messages')
  258. {
  259. $details = $this->getCatalogueDetails($catalogue);
  260. if ($details)
  261. {
  262. list($cat_id, $variant, $count) = $details;
  263. }
  264. else
  265. {
  266. return false;
  267. }
  268. $text = mysql_real_escape_string($message, $this->db);
  269. $statement = "DELETE FROM trans_unit WHERE cat_id = {$cat_id} AND source = '{$message}'";
  270. $deleted = false;
  271. mysql_query($statement, $this->db);
  272. if (mysql_affected_rows($this->db) == 1)
  273. {
  274. $deleted = $this->updateCatalogueTime($cat_id, $variant);
  275. }
  276. return $deleted;
  277. }
  278. /**
  279. * Updates the translation.
  280. *
  281. * @param string $text the source string.
  282. * @param string $target the new translation string.
  283. * @param string $comments comments
  284. * @param string $catalogue the catalogue of the translation.
  285. * @return boolean true if translation was updated, false otherwise.
  286. */
  287. function update($text, $target, $comments, $catalogue = 'messages')
  288. {
  289. $details = $this->getCatalogueDetails($catalogue);
  290. if ($details)
  291. {
  292. list($cat_id, $variant, $count) = $details;
  293. }
  294. else
  295. {
  296. return false;
  297. }
  298. $comments = mysql_real_escape_string($comments, $this->db);
  299. $target = mysql_real_escape_string($target, $this->db);
  300. $text = mysql_real_escape_string($text, $this->db);
  301. $time = time();
  302. $statement = "UPDATE trans_unit SET target = '{$target}', comments = '{$comments}', date_modified = '{$time}' WHERE cat_id = {$cat_id} AND source = '{$text}'";
  303. $updated = false;
  304. mysql_query($statement, $this->db);
  305. if (mysql_affected_rows($this->db) == 1)
  306. {
  307. $updated = $this->updateCatalogueTime($cat_id, $variant);
  308. }
  309. return $updated;
  310. }
  311. /**
  312. * Returns a list of catalogue as key and all it variants as value.
  313. *
  314. * @return array list of catalogues
  315. */
  316. function catalogues()
  317. {
  318. $statement = 'SELECT name FROM catalogue ORDER BY name';
  319. $rs = mysql_query($statement, $this->db);
  320. $result = array();
  321. while($row = mysql_fetch_array($rs, MYSQL_NUM))
  322. {
  323. $details = explode('.', $row[0]);
  324. if (!isset($details[1]))
  325. {
  326. $details[1] = null;
  327. }
  328. $result[] = $details;
  329. }
  330. return $result;
  331. }
  332. }

Debug toolbar