DbMessageSource.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\i18n;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\helpers\ArrayHelper;
  11. use yii\caching\Cache;
  12. use yii\db\Connection;
  13. use yii\db\Query;
  14. /**
  15. * DbMessageSource extends [[MessageSource]] and represents a message source that stores translated
  16. * messages in database.
  17. *
  18. * The database must contain the following two tables:
  19. *
  20. * ~~~
  21. * CREATE TABLE tbl_source_message (
  22. * id INTEGER PRIMARY KEY,
  23. * category VARCHAR(32),
  24. * message TEXT
  25. * );
  26. *
  27. * CREATE TABLE tbl_message (
  28. * id INTEGER,
  29. * language VARCHAR(16),
  30. * translation TEXT,
  31. * PRIMARY KEY (id, language),
  32. * CONSTRAINT fk_message_source_message FOREIGN KEY (id)
  33. * REFERENCES tbl_source_message (id) ON DELETE CASCADE ON UPDATE RESTRICT
  34. * );
  35. * ~~~
  36. *
  37. * The `tbl_source_message` table stores the messages to be translated, and the `tbl_message` table stores
  38. * the translated messages. The name of these two tables can be customized by setting [[sourceMessageTable]]
  39. * and [[messageTable]], respectively.
  40. *
  41. * @author resurtm <[email protected]>
  42. * @since 2.0
  43. */
  44. class DbMessageSource extends MessageSource
  45. {
  46. /**
  47. * Prefix which would be used when generating cache key.
  48. */
  49. const CACHE_KEY_PREFIX = 'DbMessageSource';
  50. /**
  51. * @var Connection|string the DB connection object or the application component ID of the DB connection.
  52. * After the DbMessageSource object is created, if you want to change this property, you should only assign
  53. * it with a DB connection object.
  54. */
  55. public $db = 'db';
  56. /**
  57. * @var Cache|string the cache object or the application component ID of the cache object.
  58. * The messages data will be cached using this cache object. Note, this property has meaning only
  59. * in case [[cachingDuration]] set to non-zero value.
  60. * After the DbMessageSource object is created, if you want to change this property, you should only assign
  61. * it with a cache object.
  62. */
  63. public $cache = 'cache';
  64. /**
  65. * @var string the name of the source message table.
  66. */
  67. public $sourceMessageTable = '{{%source_message}}';
  68. /**
  69. * @var string the name of the translated message table.
  70. */
  71. public $messageTable = '{{%message}}';
  72. /**
  73. * @var integer the time in seconds that the messages can remain valid in cache.
  74. * Use 0 to indicate that the cached data will never expire.
  75. * @see enableCaching
  76. */
  77. public $cachingDuration = 0;
  78. /**
  79. * @var boolean whether to enable caching translated messages
  80. */
  81. public $enableCaching = false;
  82. /**
  83. * Initializes the DbMessageSource component.
  84. * This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
  85. * Configured [[cache]] component would also be initialized.
  86. * @throws InvalidConfigException if [[db]] is invalid or [[cache]] is invalid.
  87. */
  88. public function init()
  89. {
  90. parent::init();
  91. if (is_string($this->db)) {
  92. $this->db = Yii::$app->getComponent($this->db);
  93. }
  94. if (!$this->db instanceof Connection) {
  95. throw new InvalidConfigException("DbMessageSource::db must be either a DB connection instance or the application component ID of a DB connection.");
  96. }
  97. if ($this->enableCaching) {
  98. if (is_string($this->cache)) {
  99. $this->cache = Yii::$app->getComponent($this->cache);
  100. }
  101. if (!$this->cache instanceof Cache) {
  102. throw new InvalidConfigException("DbMessageSource::cache must be either a cache object or the application component ID of the cache object.");
  103. }
  104. }
  105. }
  106. /**
  107. * Loads the message translation for the specified language and category.
  108. * Child classes should override this method to return the message translations of
  109. * the specified language and category.
  110. * @param string $category the message category
  111. * @param string $language the target language
  112. * @return array the loaded messages. The keys are original messages, and the values
  113. * are translated messages.
  114. */
  115. protected function loadMessages($category, $language)
  116. {
  117. if ($this->enableCaching) {
  118. $key = [
  119. __CLASS__,
  120. $category,
  121. $language,
  122. ];
  123. $messages = $this->cache->get($key);
  124. if ($messages === false) {
  125. $messages = $this->loadMessagesFromDb($category, $language);
  126. $this->cache->set($key, $messages, $this->cachingDuration);
  127. }
  128. return $messages;
  129. } else {
  130. return $this->loadMessagesFromDb($category, $language);
  131. }
  132. }
  133. /**
  134. * Loads the messages from database.
  135. * You may override this method to customize the message storage in the database.
  136. * @param string $category the message category.
  137. * @param string $language the target language.
  138. * @return array the messages loaded from database.
  139. */
  140. protected function loadMessagesFromDb($category, $language)
  141. {
  142. $query = new Query();
  143. $messages = $query->select(['t1.message message', 't2.translation translation'])
  144. ->from([$this->sourceMessageTable . ' t1', $this->messageTable . ' t2'])
  145. ->where('t1.id = t2.id AND t1.category = :category AND t2.language = :language')
  146. ->params([':category' => $category, ':language' => $language])
  147. ->createCommand($this->db)
  148. ->queryAll();
  149. return ArrayHelper::map($messages, 'message', 'translation');
  150. }
  151. }