AbstractFilesystemStorage.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @package Grav\Framework\Flex
  5. *
  6. * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
  7. * @license MIT License; see LICENSE file for details.
  8. */
  9. namespace Grav\Framework\Flex\Storage;
  10. use Grav\Common\File\CompiledJsonFile;
  11. use Grav\Common\File\CompiledMarkdownFile;
  12. use Grav\Common\File\CompiledYamlFile;
  13. use Grav\Common\Grav;
  14. use Grav\Framework\File\Formatter\JsonFormatter;
  15. use Grav\Framework\File\Formatter\MarkdownFormatter;
  16. use Grav\Framework\File\Formatter\YamlFormatter;
  17. use Grav\Framework\File\Interfaces\FileFormatterInterface;
  18. use Grav\Framework\Flex\Interfaces\FlexStorageInterface;
  19. use RocketTheme\Toolbox\File\File;
  20. use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
  21. use RuntimeException;
  22. /**
  23. * Class AbstractFilesystemStorage
  24. * @package Grav\Framework\Flex\Storage
  25. */
  26. abstract class AbstractFilesystemStorage implements FlexStorageInterface
  27. {
  28. /** @var FileFormatterInterface */
  29. protected $dataFormatter;
  30. /** @var string */
  31. protected $keyField = 'storage_key';
  32. /**
  33. * {@inheritdoc}
  34. * @see FlexStorageInterface::hasKey()
  35. */
  36. public function hasKeys(array $keys): array
  37. {
  38. $list = [];
  39. foreach ($keys as $key) {
  40. $list[$key] = $this->hasKey((string)$key);
  41. }
  42. return $list;
  43. }
  44. /**
  45. * @return string
  46. */
  47. public function getKeyField(): string
  48. {
  49. return $this->keyField;
  50. }
  51. protected function initDataFormatter($formatter): void
  52. {
  53. // Initialize formatter.
  54. if (!\is_array($formatter)) {
  55. $formatter = ['class' => $formatter];
  56. }
  57. $formatterClassName = $formatter['class'] ?? JsonFormatter::class;
  58. $formatterOptions = $formatter['options'] ?? [];
  59. $this->dataFormatter = new $formatterClassName($formatterOptions);
  60. }
  61. /**
  62. * @param string $filename
  63. * @return null|string
  64. */
  65. protected function detectDataFormatter(string $filename): ?string
  66. {
  67. if (preg_match('|(\.[a-z0-9]*)$|ui', $filename, $matches)) {
  68. switch ($matches[1]) {
  69. case '.json':
  70. return JsonFormatter::class;
  71. case '.yaml':
  72. return YamlFormatter::class;
  73. case '.md':
  74. return MarkdownFormatter::class;
  75. }
  76. }
  77. return null;
  78. }
  79. /**
  80. * @param string $filename
  81. * @return File
  82. */
  83. protected function getFile(string $filename)
  84. {
  85. $filename = $this->resolvePath($filename);
  86. switch ($this->dataFormatter->getDefaultFileExtension()) {
  87. case '.json':
  88. $file = CompiledJsonFile::instance($filename);
  89. break;
  90. case '.yaml':
  91. $file = CompiledYamlFile::instance($filename);
  92. break;
  93. case '.md':
  94. $file = CompiledMarkdownFile::instance($filename);
  95. break;
  96. default:
  97. throw new RuntimeException('Unknown extension type ' . $this->dataFormatter->getDefaultFileExtension());
  98. }
  99. return $file;
  100. }
  101. /**
  102. * @param string $path
  103. * @return string
  104. */
  105. protected function resolvePath(string $path): string
  106. {
  107. /** @var UniformResourceLocator $locator */
  108. $locator = Grav::instance()['locator'];
  109. if (!$locator->isStream($path)) {
  110. return $path;
  111. }
  112. return (string)($locator->findResource($path) ?: $locator->findResource($path, true, true));
  113. }
  114. /**
  115. * Generates a random, unique key for the row.
  116. *
  117. * @return string
  118. */
  119. protected function generateKey(): string
  120. {
  121. return substr(hash('sha256', random_bytes(32)), 0, 32);
  122. }
  123. /**
  124. * Checks if a key is valid.
  125. *
  126. * @param string $key
  127. * @return bool
  128. */
  129. protected function validateKey(string $key): bool
  130. {
  131. return (bool) preg_match('/^[^\\/\\?\\*:;{}\\\\\\n]+$/u', $key);
  132. }
  133. }