Catalog.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\g11n;
  9. use lithium\core\Libraries;
  10. /**
  11. * Globalization data is not just translated messages, it is validation rules, formats and a lot
  12. * more. Generally speaking is the `Catalog` class allowing us to retrieve and store globalized
  13. * data, providing low-level functionality to other classes.
  14. *
  15. * The class is able to aggregate data from different sources which allows to complement sparse
  16. * data. Not all categories must be supported by an individual adapter.
  17. */
  18. class Catalog extends \lithium\core\Adaptable {
  19. /**
  20. * A Collection of the configurations you add through Catalog::config().
  21. *
  22. * @var Collection
  23. */
  24. protected static $_configurations = array();
  25. /**
  26. * Libraries::locate() compatible path to adapters for this class.
  27. *
  28. * @see lithium\core\Libraries::locate()
  29. * @var string Dot-delimited path.
  30. */
  31. protected static $_adapters = 'adapter.g11n.catalog';
  32. /**
  33. * Sets configurations for this Adaptable implementation.
  34. *
  35. * @param array $config Configurations, indexed by name.
  36. * @return array `Collection` of configurations or void if setting configurations.
  37. */
  38. public static function config($config = null) {
  39. $defaults = array('scope' => null);
  40. if (is_array($config)) {
  41. foreach ($config as $i => $item) {
  42. $config[$i] += $defaults;
  43. }
  44. }
  45. return parent::config($config);
  46. }
  47. /**
  48. * Reads data.
  49. *
  50. * Results are aggregated by querying all requested configurations for the requested
  51. * locale then repeating this process for all locales down the locale cascade. This
  52. * allows for sparse data which is complemented by data from other sources or for more
  53. * generic locales. Aggregation can be controlled by either specifying the configurations
  54. * or a scope to use.
  55. *
  56. * Usage:
  57. * {{{
  58. * Catalog::read(true, 'message', 'zh');
  59. * Catalog::read('default', 'message', 'zh');
  60. * Catalog::read('default', 'validation.postalCode', 'en_US');
  61. * }}}
  62. *
  63. * @param mixed $name Provide a single configuration name as a string or multiple ones as
  64. * an array which will be used to read from. Pass `true` to use all configurations.
  65. * @param string $category A (dot-delimeted) category.
  66. * @param string $locale A locale identifier.
  67. * @param array $options Valid options are:
  68. * - `'scope'`: The scope to use.
  69. * - `'lossy'`: Whether or not to use the compact and lossy format, defaults to `true`.
  70. * @return array If available the requested data, else `null`.
  71. */
  72. public static function read($name, $category, $locale, array $options = array()) {
  73. $defaults = array('scope' => null, 'lossy' => true);
  74. $options += $defaults;
  75. $category = strtok($category, '.');
  76. $id = strtok('.');
  77. $names = $name === true ? array_keys(static::$_configurations) : (array) $name;
  78. $results = array();
  79. foreach (Locale::cascade($locale) as $cascaded) {
  80. foreach ($names as $name) {
  81. $adapter = static::adapter($name);
  82. if ($result = $adapter->read($category, $cascaded, $options['scope'])) {
  83. $results += $result;
  84. }
  85. }
  86. }
  87. if ($options['lossy']) {
  88. array_walk($results, function(&$value) {
  89. $value = $value['translated'];
  90. });
  91. }
  92. if ($id) {
  93. return isset($results[$id]) ? $results[$id] : null;
  94. }
  95. return $results ?: null;
  96. }
  97. /**
  98. * Writes data.
  99. *
  100. * Usage:
  101. * {{{
  102. * $data = array(
  103. * 'color' => '色'
  104. * );
  105. * Catalog::write('runtime', 'message', 'ja', $data);
  106. * }}}
  107. *
  108. * @param string $name Provide a configuration name to use for writing.
  109. * @param string $category A (dot-delimited) category.
  110. * @param string $locale A locale identifier.
  111. * @param mixed $data If method is used without specifying an id must be an array.
  112. * @param array $options Valid options are:
  113. * - `'scope'`: The scope to use.
  114. * @return boolean Success.
  115. */
  116. public static function write($name, $category, $locale, $data, array $options = array()) {
  117. $defaults = array('scope' => null);
  118. $options += $defaults;
  119. $category = strtok($category, '.');
  120. $id = strtok('.');
  121. if ($id) {
  122. $data = array($id => $data);
  123. }
  124. array_walk($data, function(&$value, $key) {
  125. if (!is_array($value) || !array_key_exists('translated', $value)) {
  126. $value = array('id' => $key, 'translated' => $value);
  127. }
  128. });
  129. $adapter = static::adapter($name);
  130. return $adapter->write($category, $locale, $options['scope'], $data);
  131. }
  132. }
  133. ?>