Files
watchstate/src/Libs/Entity/StateEntity.php
2022-02-16 20:22:55 +03:00

183 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Libs\Entity;
use RuntimeException;
final class StateEntity
{
public const TYPE_MOVIE = 'movie';
public const TYPE_EPISODE = 'episode';
private static array $entityKeys = [
'id',
'type',
'updated',
'watched',
'meta',
'guid_plex',
'guid_imdb',
'guid_tvdb',
'guid_tmdb',
'guid_tvmaze',
'guid_tvrage',
'guid_anidb',
];
private array $data = [];
/**
* User Addressable Variables.
*/
public null|string|int $id = null;
public string $type = '';
public int $updated = 0;
public int $watched = 0;
public array $meta = [];
public string|null $guid_plex = null;
public string|null $guid_imdb = null;
public string|null $guid_tvdb = null;
public string|null $guid_tmdb = null;
public string|null $guid_tvmaze = null;
public string|null $guid_tvrage = null;
public string|null $guid_anidb = null;
public function __construct(array $data)
{
foreach ($data as $key => $val) {
if (!in_array($key, self::$entityKeys)) {
continue;
}
if ('type' === $key && self::TYPE_MOVIE !== $val && self::TYPE_EPISODE !== $val) {
throw new RuntimeException(
sprintf(
'Unexpected type value was given. Was expecting \'%1$s or %2$s\' but got \'%3$s\' instead.',
self::TYPE_MOVIE,
self::TYPE_EPISODE,
$val
)
);
}
if ('meta' === $key && is_string($val)) {
if (null === ($val = json_decode($val, true))) {
$val = [];
}
}
$this->{$key} = $val;
}
$this->data = $this->getAll();
}
public function diff(): array
{
$changed = [];
foreach ($this->getAll() as $key => $value) {
/**
* We ignore meta on purpose as it changes frequently.
* from one server to another.
*/
if ('meta' === $key) {
continue;
}
if ($value === ($this->data[$key] ?? null)) {
continue;
}
$changed['new'][$key] = $value ?? 'None';
$changed['old'][$key] = $this->data[$key] ?? 'None';
}
return $changed;
}
public function getAll(): array
{
return array_intersect_key((array)$this, array_flip(self::$entityKeys));
}
public function isChanged(): bool
{
return count($this->diff()) >= 1;
}
public function hasGuids(): bool
{
foreach ($this->getAll() as $key => $val) {
if (null !== $this->{$key} && str_starts_with($key, 'guid_')) {
return true;
}
}
return false;
}
public function apply(StateEntity $entity, bool $guidOnly = false): self
{
if ($this->isEqual($entity)) {
return $this;
}
foreach ($entity->getAll() as $key => $val) {
if (true === $guidOnly && !str_starts_with($key, 'guid_')) {
continue;
}
$this->updateValue($key, $entity);
}
return $this;
}
private function isEqual(StateEntity $entity): bool
{
foreach ($this->getAll() as $key => $val) {
$checkedValue = $this->isEqualValue($key, $entity);
if (false === $checkedValue) {
return false;
}
}
return true;
}
private function isEqualValue(string $key, StateEntity $entity): bool
{
if ($key === 'updated' || $key === 'watched') {
return !($entity->updated > $this->updated && $entity->watched !== $this->watched);
}
if (null !== ($entity->{$key} ?? null) && $this->{$key} !== $entity->{$key}) {
return false;
}
return true;
}
private function updateValue(string $key, StateEntity $entity): void
{
if ($key === 'updated' || $key === 'watched') {
if ($entity->updated > $this->updated && $entity->watched !== $this->watched) {
$this->updated = $entity->updated;
$this->watched = $entity->watched;
}
return;
}
if (null !== ($entity->{$key} ?? null) && $this->{$key} !== $entity->{$key}) {
$this->{$key} = $entity->{$key};
}
}
public static function getEntityKeys(): array
{
return self::$entityKeys;
}
}