Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
4.4 KiB

3 years ago
3 years ago
  1. <?php
  2. namespace Friendica\Core;
  3. use Friendica\Database\DBA;
  4. use Friendica\Model\Storage\IStorage;
  5. /**
  6. * @brief Manage storage backends
  7. *
  8. * Core code uses this class to get and set current storage backend class.
  9. * Addons use this class to register and unregister additional backends.
  10. */
  11. class StorageManager
  12. {
  13. private static $default_backends = [
  14. 'Filesystem' => \Friendica\Model\Storage\Filesystem::class,
  15. 'Database' => \Friendica\Model\Storage\Database::class,
  16. ];
  17. private static $backends = [];
  18. private static function setup()
  19. {
  20. if (count(self::$backends)==0) {
  21. self::$backends = Config::get('storage', 'backends', self::$default_backends);
  22. }
  23. }
  24. /**
  25. * @brief Return current storage backend class
  26. * @return string
  27. * @throws \Friendica\Network\HTTPException\InternalServerErrorException
  28. */
  29. public static function getBackend()
  30. {
  31. return Config::get('storage', 'class', '');
  32. }
  33. /**
  34. * @brief Return storage backend class by registered name
  35. *
  36. * @param string $name Backend name
  37. * @return string Empty if no backend registered at $name exists
  38. */
  39. public static function getByName($name)
  40. {
  41. self::setup();
  42. return defaults(self::$backends, $name, '');
  43. }
  44. /**
  45. * @brief Set current storage backend class
  46. *
  47. * @param string $class Backend class name
  48. * @throws \Friendica\Network\HTTPException\InternalServerErrorException
  49. */
  50. public static function setBackend($class)
  51. {
  52. /// @todo Check that $class implements IStorage
  53. Config::set('storage', 'class', $class);
  54. }
  55. /**
  56. * @brief Get registered backends
  57. *
  58. * @return array
  59. */
  60. public static function listBackends()
  61. {
  62. self::setup();
  63. return self::$backends;
  64. }
  65. /**
  66. * @brief Register a storage backend class
  67. *
  68. * @param string $name User readable backend name
  69. * @param string $class Backend class name
  70. * @throws \Friendica\Network\HTTPException\InternalServerErrorException
  71. */
  72. public static function register($name, $class)
  73. {
  74. /// @todo Check that $class implements IStorage
  75. self::setup();
  76. self::$backends[$name] = $class;
  77. Config::set('storage', 'backends', self::$backends);
  78. }
  79. /**
  80. * @brief Unregister a storage backend class
  81. *
  82. * @param string $name User readable backend name
  83. * @throws \Friendica\Network\HTTPException\InternalServerErrorException
  84. */
  85. public static function unregister($name)
  86. {
  87. self::setup();
  88. unset(self::$backends[$name]);
  89. Config::set('storage', 'backends', self::$backends);
  90. }
  91. /**
  92. * @brief Move resources to storage $dest
  93. *
  94. * Copy existing data to destination storage and delete from source.
  95. * This method cannot move to legacy in-table `data` field.
  96. *
  97. * @param string $dest Destination storage class name
  98. * @param array $tables Tables to look in for resources. Optional, defaults to ['photo', 'attach']
  99. *
  100. * @throws \Exception
  101. * @return int Number of moved resources
  102. */
  103. public static function move($dest, $tables = null)
  104. {
  105. if (is_null($dest) || empty($dest)) {
  106. throw new \Exception('Can\'t move to NULL storage backend');
  107. }
  108. if (is_null($tables)) {
  109. $tables = ['photo', 'attach'];
  110. }
  111. $moved = 0;
  112. foreach ($tables as $table) {
  113. // Get the rows where backend class is not the destination backend class
  114. $rr = DBA::select(
  115. $table,
  116. ['id', 'data', 'backend-class', 'backend-ref'],
  117. ['`backend-class` IS NULL or `backend-class` != ?' , $dest ]
  118. );
  119. if (DBA::isResult($rr)) {
  120. while($r = DBA::fetch($rr)) {
  121. $id = $r['id'];
  122. $data = $r['data'];
  123. /** @var IStorage $backendClass */
  124. $backendClass = $r['backend-class'];
  125. $backendRef = $r['backend-ref'];
  126. if (!is_null($backendClass) && $backendClass !== '') {
  127. Logger::log("get data from old backend " . $backendClass . " : " . $backendRef);
  128. $data = $backendClass::get($backendRef);
  129. }
  130. Logger::log("save data to new backend " . $dest);
  131. /** @var IStorage $dest */
  132. $ref = $dest::put($data);
  133. Logger::log("saved data as " . $ref);
  134. if ($ref !== '') {
  135. Logger::log("update row");
  136. $ru = DBA::update($table, ['backend-class' => $dest, 'backend-ref' => $ref, 'data' => ''], ['id' => $id]);
  137. if ($ru) {
  138. if (!is_null($backendClass) && $backendClass !== '') {
  139. Logger::log("delete data from old backend " . $backendClass . " : " . $backendRef);
  140. $backendClass::delete($backendRef);
  141. }
  142. $moved++;
  143. }
  144. }
  145. }
  146. }
  147. }
  148. return $moved;
  149. }
  150. }