Datalist.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace Elgg\Database;
  3. use Elgg\Cache\Pool;
  4. use Elgg\Database;
  5. use Elgg\Logger;
  6. /**
  7. * Persistent, installation-wide key-value storage.
  8. *
  9. * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
  10. *
  11. * @access private
  12. *
  13. * @package Elgg.Core
  14. * @subpackage Database
  15. * @since 1.10.0
  16. */
  17. class Datalist {
  18. /** @var Pool */
  19. private $cache;
  20. /** @var Database */
  21. private $db;
  22. /** @var Logger */
  23. private $logger;
  24. /** @var string */
  25. private $table;
  26. /**
  27. * Constructor
  28. *
  29. * @param Pool $cache Some kind of caching implementation
  30. * @param Database $db The database
  31. * @param Logger $logger A logger
  32. * @param string $table The name of the datalists table, including prefix
  33. */
  34. public function __construct(Pool $cache, Database $db, Logger $logger, $table) {
  35. $this->cache = $cache;
  36. $this->db = $db;
  37. $this->logger = $logger;
  38. $this->table = $table;
  39. }
  40. /**
  41. * Get the value of a datalist element.
  42. *
  43. * Plugin authors should use elgg_get_config() and pass null for the site GUID.
  44. *
  45. * @internal Datalists are stored in the datalist table.
  46. *
  47. * @tip Use datalists to store information common to a full installation.
  48. *
  49. * @param string $name The name of the datalist
  50. * @return string|null|false String if value exists, null if doesn't, false on error
  51. * @access private
  52. */
  53. function get($name) {
  54. $name = trim($name);
  55. // cannot store anything longer than 255 characters in db, so catch here
  56. if (elgg_strlen($name) > 255) {
  57. $this->logger->error("The name length for configuration variables cannot be greater than 255");
  58. return false;
  59. }
  60. return $this->cache->get($name, function() use ($name) {
  61. $escaped_name = $this->db->sanitizeString($name);
  62. $result = $this->db->getDataRow("SELECT * FROM {$this->table} WHERE name = '$escaped_name'");
  63. return $result ? $result->value : null;
  64. });
  65. }
  66. /**
  67. * Set the value for a datalist element.
  68. *
  69. * Plugin authors should use elgg_save_config() and pass null for the site GUID.
  70. *
  71. * @warning Names should be selected so as not to collide with the names for the
  72. * site config.
  73. *
  74. * @warning Values set here are not available in $CONFIG until next page load.
  75. *
  76. * @param string $name The name of the datalist
  77. * @param string $value The new value
  78. *
  79. * @return bool
  80. * @access private
  81. */
  82. function set($name, $value) {
  83. $name = trim($name);
  84. // cannot store anything longer than 255 characters in db, so catch before we set
  85. if (elgg_strlen($name) > 255) {
  86. $this->logger->error("The name length for configuration variables cannot be greater than 255");
  87. return false;
  88. }
  89. $escaped_name = $this->db->sanitizeString($name);
  90. $escaped_value = $this->db->sanitizeString($value);
  91. $success = $this->db->insertData("INSERT INTO {$this->table}"
  92. . " SET name = '$escaped_name', value = '$escaped_value'"
  93. . " ON DUPLICATE KEY UPDATE value = '$escaped_value'");
  94. $this->cache->put($name, $value);
  95. return $success !== false;
  96. }
  97. /**
  98. * Load entire datalist in memory.
  99. *
  100. * This could cause OOM problems if the datalists table is large.
  101. *
  102. * @todo make a list of datalists that we want to get in one grab
  103. *
  104. * @return array
  105. * @access private
  106. */
  107. function loadAll() {
  108. $result = $this->db->getData("SELECT * FROM {$this->table}");
  109. $map = array();
  110. if (is_array($result)) {
  111. foreach ($result as $row) {
  112. $map[$row->name] = $row->value;
  113. $this->cache->put($row->name, $row->value);
  114. }
  115. }
  116. return $map;
  117. }
  118. /**
  119. * Run a function one time per installation.
  120. *
  121. * If you pass a timestamp as the second argument, it will run the function
  122. * only if (i) it has never been run before or (ii) the timestamp is >=
  123. * the last time it was run.
  124. *
  125. * @warning Functions are determined by their name. If you change the name of a function
  126. * it will be run again.
  127. *
  128. * @tip Use $timelastupdatedcheck in your plugins init function to perform automated
  129. * upgrades. Schedule a function to run once and pass the timestamp of the new release.
  130. * This will cause the run once function to be run on all installations. To perform
  131. * additional upgrades, create new functions for each release.
  132. *
  133. * @warning The function name cannot be longer than 255 characters long due to
  134. * the current schema for the datalist table.
  135. *
  136. * @internal A datalist entry $functioname is created with the value of time().
  137. *
  138. * @param string $functionname The name of the function you want to run.
  139. * @param int $timelastupdatedcheck A UNIX timestamp. If time() is > than this,
  140. * this function will be run again.
  141. *
  142. * @return bool
  143. * @todo deprecate
  144. */
  145. function runFunctionOnce($functionname, $timelastupdatedcheck = 0) {
  146. $lastupdated = $this->get($functionname);
  147. if ($lastupdated) {
  148. $lastupdated = (int) $lastupdated;
  149. } elseif ($lastupdated !== false) {
  150. $lastupdated = 0;
  151. } else {
  152. // unable to check datalist
  153. return false;
  154. }
  155. if (is_callable($functionname) && $lastupdated <= $timelastupdatedcheck) {
  156. $functionname();
  157. $this->set($functionname, time());
  158. return true;
  159. } else {
  160. return false;
  161. }
  162. }
  163. }