AbstractMedia.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * @package Grav\Common\Page
  4. *
  5. * @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Common\Page\Medium;
  9. use Grav\Common\Config\Config;
  10. use Grav\Common\Data\Blueprint;
  11. use Grav\Common\Grav;
  12. use Grav\Common\Language\Language;
  13. use Grav\Common\Media\Interfaces\MediaCollectionInterface;
  14. use Grav\Common\Media\Interfaces\MediaObjectInterface;
  15. use Grav\Common\Media\Interfaces\MediaUploadInterface;
  16. use Grav\Common\Media\Traits\MediaUploadTrait;
  17. use Grav\Common\Page\Pages;
  18. use Grav\Common\Utils;
  19. use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
  20. use RocketTheme\Toolbox\ArrayTraits\Countable;
  21. use RocketTheme\Toolbox\ArrayTraits\Export;
  22. use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
  23. use RocketTheme\Toolbox\ArrayTraits\Iterator;
  24. use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
  25. use function is_array;
  26. /**
  27. * Class AbstractMedia
  28. * @package Grav\Common\Page\Medium
  29. */
  30. abstract class AbstractMedia implements ExportInterface, MediaCollectionInterface, MediaUploadInterface
  31. {
  32. use ArrayAccess;
  33. use Countable;
  34. use Iterator;
  35. use Export;
  36. use MediaUploadTrait;
  37. /** @var array */
  38. protected $items = [];
  39. /** @var string|null */
  40. protected $path;
  41. /** @var array */
  42. protected $images = [];
  43. /** @var array */
  44. protected $videos = [];
  45. /** @var array */
  46. protected $audios = [];
  47. /** @var array */
  48. protected $files = [];
  49. /** @var array|null */
  50. protected $media_order;
  51. /**
  52. * Return media path.
  53. *
  54. * @return string|null
  55. */
  56. public function getPath(): ?string
  57. {
  58. return $this->path;
  59. }
  60. /**
  61. * @param string|null $path
  62. * @return void
  63. */
  64. public function setPath(?string $path): void
  65. {
  66. $this->path = $path;
  67. }
  68. /**
  69. * Get medium by filename.
  70. *
  71. * @param string $filename
  72. * @return MediaObjectInterface|null
  73. */
  74. public function get($filename)
  75. {
  76. return $this->offsetGet($filename);
  77. }
  78. /**
  79. * Call object as function to get medium by filename.
  80. *
  81. * @param string $filename
  82. * @return mixed
  83. */
  84. #[\ReturnTypeWillChange]
  85. public function __invoke($filename)
  86. {
  87. return $this->offsetGet($filename);
  88. }
  89. /**
  90. * Set file modification timestamps (query params) for all the media files.
  91. *
  92. * @param string|int|null $timestamp
  93. * @return $this
  94. */
  95. public function setTimestamps($timestamp = null)
  96. {
  97. foreach ($this->items as $instance) {
  98. $instance->setTimestamp($timestamp);
  99. }
  100. return $this;
  101. }
  102. /**
  103. * Get a list of all media.
  104. *
  105. * @return MediaObjectInterface[]
  106. */
  107. public function all()
  108. {
  109. $this->items = $this->orderMedia($this->items);
  110. return $this->items;
  111. }
  112. /**
  113. * Get a list of all image media.
  114. *
  115. * @return MediaObjectInterface[]
  116. */
  117. public function images()
  118. {
  119. $this->images = $this->orderMedia($this->images);
  120. return $this->images;
  121. }
  122. /**
  123. * Get a list of all video media.
  124. *
  125. * @return MediaObjectInterface[]
  126. */
  127. public function videos()
  128. {
  129. $this->videos = $this->orderMedia($this->videos);
  130. return $this->videos;
  131. }
  132. /**
  133. * Get a list of all audio media.
  134. *
  135. * @return MediaObjectInterface[]
  136. */
  137. public function audios()
  138. {
  139. $this->audios = $this->orderMedia($this->audios);
  140. return $this->audios;
  141. }
  142. /**
  143. * Get a list of all file media.
  144. *
  145. * @return MediaObjectInterface[]
  146. */
  147. public function files()
  148. {
  149. $this->files = $this->orderMedia($this->files);
  150. return $this->files;
  151. }
  152. /**
  153. * @param string $name
  154. * @param MediaObjectInterface|null $file
  155. * @return void
  156. */
  157. public function add($name, $file)
  158. {
  159. if (null === $file) {
  160. return;
  161. }
  162. $this->offsetSet($name, $file);
  163. switch ($file->type) {
  164. case 'image':
  165. $this->images[$name] = $file;
  166. break;
  167. case 'video':
  168. $this->videos[$name] = $file;
  169. break;
  170. case 'audio':
  171. $this->audios[$name] = $file;
  172. break;
  173. default:
  174. $this->files[$name] = $file;
  175. }
  176. }
  177. /**
  178. * @param string $name
  179. * @return void
  180. */
  181. public function hide($name)
  182. {
  183. $this->offsetUnset($name);
  184. unset($this->images[$name], $this->videos[$name], $this->audios[$name], $this->files[$name]);
  185. }
  186. /**
  187. * Create Medium from a file.
  188. *
  189. * @param string $file
  190. * @param array $params
  191. * @return Medium|null
  192. */
  193. public function createFromFile($file, array $params = [])
  194. {
  195. return MediumFactory::fromFile($file, $params);
  196. }
  197. /**
  198. * Create Medium from array of parameters
  199. *
  200. * @param array $items
  201. * @param Blueprint|null $blueprint
  202. * @return Medium|null
  203. */
  204. public function createFromArray(array $items = [], Blueprint $blueprint = null)
  205. {
  206. return MediumFactory::fromArray($items, $blueprint);
  207. }
  208. /**
  209. * @param MediaObjectInterface $mediaObject
  210. * @return ImageFile
  211. */
  212. public function getImageFileObject(MediaObjectInterface $mediaObject): ImageFile
  213. {
  214. return ImageFile::open($mediaObject->get('filepath'));
  215. }
  216. /**
  217. * Order the media based on the page's media_order
  218. *
  219. * @param array $media
  220. * @return array
  221. */
  222. protected function orderMedia($media)
  223. {
  224. if (null === $this->media_order) {
  225. $path = $this->getPath();
  226. if (null !== $path) {
  227. /** @var Pages $pages */
  228. $pages = Grav::instance()['pages'];
  229. $page = $pages->get($path);
  230. if ($page && isset($page->header()->media_order)) {
  231. $this->media_order = array_map('trim', explode(',', $page->header()->media_order));
  232. }
  233. }
  234. }
  235. if (!empty($this->media_order) && is_array($this->media_order)) {
  236. $media = Utils::sortArrayByArray($media, $this->media_order);
  237. } else {
  238. ksort($media, SORT_NATURAL | SORT_FLAG_CASE);
  239. }
  240. return $media;
  241. }
  242. protected function fileExists(string $filename, string $destination): bool
  243. {
  244. return file_exists("{$destination}/{$filename}");
  245. }
  246. /**
  247. * Get filename, extension and meta part.
  248. *
  249. * @param string $filename
  250. * @return array
  251. */
  252. protected function getFileParts($filename)
  253. {
  254. if (preg_match('/(.*)@(\d+)x\.(.*)$/', $filename, $matches)) {
  255. $name = $matches[1];
  256. $extension = $matches[3];
  257. $extra = (int) $matches[2];
  258. $type = 'alternative';
  259. if ($extra === 1) {
  260. $type = 'base';
  261. $extra = null;
  262. }
  263. } else {
  264. $fileParts = explode('.', $filename);
  265. $name = array_shift($fileParts);
  266. $extension = null;
  267. $extra = null;
  268. $type = 'base';
  269. while (($part = array_shift($fileParts)) !== null) {
  270. if ($part !== 'meta' && $part !== 'thumb') {
  271. if (null !== $extension) {
  272. $name .= '.' . $extension;
  273. }
  274. $extension = $part;
  275. } else {
  276. $type = $part;
  277. $extra = '.' . $part . '.' . implode('.', $fileParts);
  278. break;
  279. }
  280. }
  281. }
  282. return [$name, $extension, $type, $extra];
  283. }
  284. protected function getGrav(): Grav
  285. {
  286. return Grav::instance();
  287. }
  288. protected function getConfig(): Config
  289. {
  290. return $this->getGrav()['config'];
  291. }
  292. protected function getLanguage(): Language
  293. {
  294. return $this->getGrav()['language'];
  295. }
  296. protected function clearCache(): void
  297. {
  298. /** @var UniformResourceLocator $locator */
  299. $locator = $this->getGrav()['locator'];
  300. $locator->clearCache();
  301. }
  302. }