<?php
namespace App\Model\Content\Media;
use App\Model\Content\Media;
use ArrayAccess;
use JsonSerializable;
use Symfony\Component\HttpFoundation\ParameterBag;
abstract class AbstractMedia implements JsonSerializable, ArrayAccess
{
public const TYPE = null;
protected const TYPES = [
Media\ImageLooseMedia::TYPE => Media\ImageLooseMedia::class,
Media\YoutubeVideoMedia::TYPE => Media\YoutubeVideoMedia::class,
Media\VimeoVideoMedia::TYPE => Media\VimeoVideoMedia::class,
Media\DocumentLooseMedia::TYPE => Media\DocumentLooseMedia::class,
Media\GoogleDocumentMedia::TYPE => Media\GoogleDocumentMedia::class,
];
protected const IMAGE_TYPES = [
Media\ImageLooseMedia::TYPE,
];
protected const VIDEO_TYPES = [
Media\YoutubeVideoMedia::TYPE,
Media\VimeoVideoMedia::TYPE,
];
protected const AUDIO_TYPES = [];
protected const DOCUMENT_TYPES = [
Media\DocumentLooseMedia::TYPE,
Media\GoogleDocumentMedia::TYPE,
];
public const DECORS__META = 'meta';
public const DECORS__URLS = 'urls';
public const DECORS__UPLOADS = 'uploads';
protected const PARAMS__FEATURED = 'featured';
protected const PARAMS__NOTE = 'note';
protected const PARAMS__ALT = 'alt';
// NOTE: these are carried over from old gallery module, currently unused...
protected const PARAMS__TITLE = 'title';
protected const PARAMS__HIDDEN = 'hidden';
/**
* @var string|null
*/
protected ?string $id = null;
/**
* @var ParameterBag
*/
protected ParameterBag $params;
/**
* @var ParameterBag
*/
protected ParameterBag $decors;
/**
* @param AbstractMedia|array $data
* @return self
*/
public static function build($data): self
{
// if we already have an abstract media, return it; just a helper to make other logic less verbose
if ($data instanceof self) {
return $data;
}
// determine the type
$type = $data['type'];
// determine the class and ensure it is legit
$class = self::TYPES[$type];
if ( ! is_subclass_of($class, self::class)) {
throw new \RuntimeException();
}
// build an object of the proper type
return new $class($data);
}
/**
* @param array|null $data
*/
public function __construct(?array $data = null)
{
// set up the basic params
$this->params = new ParameterBag([
self::PARAMS__FEATURED => false,
self::PARAMS__NOTE => null,
self::PARAMS__ALT => null,
]);
// init the decorations
$this->decors = new ParameterBag();
// if there is data, handle it
if ($data) {
$this->parseArray($data);
}
}
/**
* @return array
* @throws \Exception
*/
public function toArray(): array
{
$data = [
'type' => $this->getType(),
'id' => $this->getId(),
'params' => $this->getParams()->all(),
];
foreach ($this->getDecorations()->keys() as $key) {
$data['_'.$key] = $this->getDecorations()->get($key);
}
return $data;
}
/**
* {@inheritDoc}
*/
public function jsonSerialize(): array
{
return $this->toArray();
}
/**
* @return string
*/
public function getType(): string
{
if ( ! static::TYPE) {
throw new \LogicException();
}
return static::TYPE;
}
/**
* @return bool
*/
public function isImage(): bool
{
return in_array(
$this->getType(),
self::IMAGE_TYPES,
true,
);
}
/**
* @return bool
*/
public function isVideo(): bool
{
return in_array(
$this->getType(),
self::VIDEO_TYPES,
true,
);
}
/**
* @return bool
*/
public function isAudio(): bool
{
return in_array(
$this->getType(),
self::AUDIO_TYPES,
true,
);
}
/**
* @return bool
*/
public function isDocument(): bool
{
return in_array(
$this->getType(),
self::DOCUMENT_TYPES,
true,
);
}
/**
* @return string|null
*/
public function getId(): ?string
{
return $this->id;
}
/**
* @param string $id
* @return $this
*/
public function setId(string $id): self
{
$this->id = $id;
return $this;
}
/**
* @return ParameterBag
*/
public function getParams(): ParameterBag
{
return $this->params;
}
/**
* @return ParameterBag
*/
public function getDecorations(): ParameterBag
{
return $this->decors;
}
/**
* @param array $data
* @return void
*/
protected function parseArray(array $data): void
{
// set the id value
$this->setId($data['id']);
// replace the params
$this->params->replace($data['params'] ?: []);
// need to clear the decorations
$this->decors->replace([]);
}
/**
* @return bool
*/
public function isFeatured(): bool
{
return ($this->getParams()->getBoolean(self::PARAMS__FEATURED) === true);
}
/**
* @param bool $featured
* @return $this
*/
public function setFeatured(bool $featured): self
{
$this->getParams()->set(self::PARAMS__FEATURED, $featured);
return $this;
}
/**
* @return string|null
*/
public function getNote(): ?string
{
return $this->getParams()->get(self::PARAMS__NOTE) ?: null;
}
/**
* @param string|null $note
* @return $this
*/
public function setNote(?string $note): self
{
$this->getParams()->set(self::PARAMS__NOTE, trim($note) ?: null);
return $this;
}
/**
* @return string|null
*/
public function getAlt(): ?string
{
return $this->getParams()->get(self::PARAMS__ALT) ?: null;
}
/**
* @param string|null $alt
* @return $this
*/
public function setAlt(?string $alt): self
{
$this->getParams()->set(self::PARAMS__ALT, trim($alt) ?: null);
return $this;
}
/**
* @return string|null
*/
public function getTitle(): ?string
{
return $this->getParams()->get(self::PARAMS__TITLE) ?: null;
}
/**
* @param string|null $title
* @return $this
*/
public function setTitle(?string $title): self
{
$this->getParams()->set(self::PARAMS__TITLE, trim($title) ?: null);
return $this;
}
/**
* @return bool
*/
public function isHidden(): bool
{
return $this->getParams()->get(self::PARAMS__HIDDEN) ?: false;
}
/**
* @param bool|null $hidden
* @return $this
*/
public function setHidden(?bool $hidden): self
{
$this->getParams()->set(self::PARAMS__HIDDEN, $hidden ?: false);
return $this;
}
/**
* @param string $name
* @return mixed
*/
public function __get(string $name)
{
if (str_starts_with($name, '_')) {
$name = ltrim($name, '_');
if ( ! $this->getDecorations()->has($name)) {
throw new \RuntimeException();
}
return $this->getDecorations()->get($name);
}
throw new \RuntimeException();
}
/**
* @param string $name
* @return bool
*/
public function __isset(string $name): bool
{
if (str_starts_with($name, '_')) {
$name = ltrim($name, '_');
return $this->getDecorations()->has($name);
}
return false;
}
/**
* {@inheritDoc}
*/
public function offsetExists($offset): bool
{
if (str_starts_with($offset, '_')) {
return $this->decors->has($offset);
}
return $this->params->has($offset);
}
/**
* {@inheritDoc}
*/
public function offsetGet($offset)
{
if (str_starts_with($offset, '_')) {
return $this->decors->get($offset);
}
return $this->params->get($offset);
}
/**
* {@inheritDoc}
*/
public function offsetSet($offset, $value): void
{
if (str_starts_with($offset, '_')) {
$this->decors->set($offset, $value);
} else {
$this->params->set($offset, $value);
}
}
/**
* {@inheritDoc}
*/
public function offsetUnset($offset): void
{
if (str_starts_with($offset, '_')) {
$this->decors->remove($offset);
} else {
$this->params->remove($offset);
}
}
}