MediaObject.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php declare(strict_types=1);
  2. namespace Grav\Framework\Media;
  3. use Grav\Common\Page\Medium\ImageMedium;
  4. use Grav\Framework\Contracts\Media\MediaObjectInterface;
  5. use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
  6. use Grav\Framework\Media\Interfaces\MediaObjectInterface as GravMediaObjectInterface;
  7. use Grav\Framework\Psr7\Response;
  8. use Psr\Http\Message\ResponseInterface;
  9. use Throwable;
  10. /**
  11. * Class MediaObject
  12. */
  13. class MediaObject implements MediaObjectInterface
  14. {
  15. /** @var string */
  16. static public $placeholderImage = 'image://media/thumb.png';
  17. /** @var FlexObjectInterface */
  18. public $object;
  19. /** @var GravMediaObjectInterface|null */
  20. public $media;
  21. /** @var string|null */
  22. private $field;
  23. /** @var string */
  24. private $filename;
  25. /**
  26. * MediaObject constructor.
  27. * @param string|null $field
  28. * @param string $filename
  29. * @param GravMediaObjectInterface|null $media
  30. * @param FlexObjectInterface $object
  31. */
  32. public function __construct(?string $field, string $filename, ?GravMediaObjectInterface $media, FlexObjectInterface $object)
  33. {
  34. $this->field = $field;
  35. $this->filename = $filename;
  36. $this->media = $media;
  37. $this->object = $object;
  38. }
  39. /**
  40. * @return string
  41. */
  42. public function getType(): string
  43. {
  44. return 'media';
  45. }
  46. /**
  47. * @return string
  48. */
  49. public function getId(): string
  50. {
  51. $field = $this->field;
  52. $object = $this->object;
  53. $path = $field ? "/{$field}/" : '/media/';
  54. return $object->getType() . '/' . $object->getKey() . $path . basename($this->filename);
  55. }
  56. /**
  57. * @return bool
  58. */
  59. public function exists(): bool
  60. {
  61. return $this->media !== null;
  62. }
  63. /**
  64. * @return array
  65. */
  66. public function getMeta(): array
  67. {
  68. if (!isset($this->media)) {
  69. return [];
  70. }
  71. return $this->media->getMeta();
  72. }
  73. /**
  74. * @param string $field
  75. * @return mixed|null
  76. */
  77. public function get(string $field)
  78. {
  79. if (!isset($this->media)) {
  80. return null;
  81. }
  82. return $this->media->get($field);
  83. }
  84. /**
  85. * @return string
  86. */
  87. public function getUrl(): string
  88. {
  89. if (!isset($this->media)) {
  90. return '';
  91. }
  92. return $this->media->url();
  93. }
  94. /**
  95. * Create media response.
  96. *
  97. * @param array $actions
  98. * @return Response
  99. */
  100. public function createResponse(array $actions): ResponseInterface
  101. {
  102. if (!isset($this->media)) {
  103. return $this->create404Response($actions);
  104. }
  105. $media = $this->media;
  106. if ($actions) {
  107. $media = $this->processMediaActions($media, $actions);
  108. }
  109. // FIXME: This only works for images
  110. if (!$media instanceof ImageMedium) {
  111. throw new \RuntimeException('Not Implemented', 500);
  112. }
  113. $filename = $media->path(false);
  114. $time = filemtime($filename);
  115. $size = filesize($filename);
  116. $body = fopen($filename, 'rb');
  117. $headers = [
  118. 'Content-Type' => $media->get('mime'),
  119. 'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
  120. 'ETag' => sprintf('%x-%x', $size, $time)
  121. ];
  122. return new Response(200, $headers, $body);
  123. }
  124. /**
  125. * Process media actions
  126. *
  127. * @param GravMediaObjectInterface $medium
  128. * @param array $actions
  129. * @return GravMediaObjectInterface
  130. */
  131. protected function processMediaActions(GravMediaObjectInterface $medium, array $actions): GravMediaObjectInterface
  132. {
  133. // loop through actions for the image and call them
  134. foreach ($actions as $method => $params) {
  135. $matches = [];
  136. if (preg_match('/\[(.*)]/', $params, $matches)) {
  137. $args = [explode(',', $matches[1])];
  138. } else {
  139. $args = explode(',', $params);
  140. }
  141. try {
  142. $medium->{$method}(...$args);
  143. } catch (Throwable $e) {
  144. // Ignore all errors for now and just skip the action.
  145. }
  146. }
  147. return $medium;
  148. }
  149. /**
  150. * @param array $actions
  151. * @return Response
  152. */
  153. protected function create404Response(array $actions): Response
  154. {
  155. // Display placeholder image.
  156. $filename = static::$placeholderImage;
  157. $time = filemtime($filename);
  158. $size = filesize($filename);
  159. $body = fopen($filename, 'rb');
  160. $headers = [
  161. 'Content-Type' => 'image/svg',
  162. 'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
  163. 'ETag' => sprintf('%x-%x', $size, $time)
  164. ];
  165. return new Response(404, $headers, $body);
  166. }
  167. /**
  168. * @return array
  169. */
  170. public function jsonSerialize(): array
  171. {
  172. return [
  173. 'type' => $this->getType(),
  174. 'id' => $this->getId()
  175. ];
  176. }
  177. /**
  178. * @return string[]
  179. */
  180. public function __debugInfo(): array
  181. {
  182. return $this->jsonSerialize();
  183. }
  184. }