Files
watchstate/src/Libs/Guid.php
2022-07-16 19:37:27 +03:00

245 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Libs;
use InvalidArgumentException;
use JsonSerializable;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Stringable;
final class Guid implements JsonSerializable, Stringable
{
public const GUID_IMDB = 'guid_imdb';
public const GUID_TVDB = 'guid_tvdb';
public const GUID_TMDB = 'guid_tmdb';
public const GUID_TVMAZE = 'guid_tvmaze';
public const GUID_TVRAGE = 'guid_tvrage';
public const GUID_ANIDB = 'guid_anidb';
private const SUPPORTED = [
Guid::GUID_IMDB => 'string',
Guid::GUID_TVDB => 'string',
Guid::GUID_TMDB => 'string',
Guid::GUID_TVMAZE => 'string',
Guid::GUID_TVRAGE => 'string',
Guid::GUID_ANIDB => 'string',
];
private const VALIDATE_GUID = [
Guid::GUID_IMDB => [
'pattern' => '/tt(\d+)/i',
'example' => 'tt(number)',
]
];
private const LOOKUP_KEY = '{db}://{id}';
private array $data = [];
private static LoggerInterface|null $logger = null;
/**
* Create List of db => external id list.
*
* @param array $guids Key/value pair of db => external id. For example, [ "guid_imdb" => "tt123456789" ]
* @param array $context
*/
public function __construct(array $guids, array $context = [])
{
foreach ($guids as $key => $value) {
if (null === $value || null === (self::SUPPORTED[$key] ?? null)) {
continue;
}
if ($value === ($this->data[$key] ?? null)) {
continue;
}
if (false === is_string($key)) {
$this->getLogger()->info(
'Ignoring [%(backend)] %(item.type) [%(item.title)] external id. Unexpected key type [%(given)] was given.',
[
'key' => (string)$key,
'given' => get_debug_type($key),
...$context,
]
);
continue;
}
if (null === (self::SUPPORTED[$key] ?? null)) {
$this->getLogger()->info(
'Ignoring [%(backend)] %(item.type) [%(item.title)] [%(key)] external id. Not supported.',
[
'key' => $key,
...$context,
]
);
continue;
}
if (self::SUPPORTED[$key] !== ($valueType = get_debug_type($value))) {
$this->getLogger()->info(
'Ignoring [%(backend)] %(item.type) [%(item.title)] [%(key)] external id. Unexpected value type.',
[
'key' => $key,
'condition' => [
'expecting' => self::SUPPORTED[$key],
'actual' => $valueType,
],
...$context,
]
);
continue;
}
if (null !== (self::VALIDATE_GUID[$key] ?? null)) {
if (1 !== preg_match(self::VALIDATE_GUID[$key]['pattern'], $value)) {
$this->getLogger()->info(
'Ignoring [%(backend)] %(item.type) [%(item.title)] [%(key)] external id. Unexpected [%(given)] value, expecting [%(expected)].',
[
'key' => $key,
'expected' => self::VALIDATE_GUID[$key]['example'],
'given' => $value,
...$context,
]
);
continue;
}
}
$this->data[$key] = $value;
}
}
/**
* Set Logger.
*
* @param LoggerInterface $logger
* @return void
*/
public static function setLogger(LoggerInterface $logger): void
{
self::$logger = $logger;
}
/**
* Get Supported External ids sources.
*
* @return array<string,string>
*/
public static function getSupported(): array
{
return self::SUPPORTED;
}
/**
* Create new instance from array.
*
* @param array $payload array of [ 'key' => 'value' ] pairs of [ 'db_source' => 'external id' ].
* @param array $context
*
* @return self
*/
public static function fromArray(array $payload, array $context = []): self
{
return new self(guids: $payload, context: $context);
}
/**
* Validate id value against expected format.
*
* @param string $db guid source
* @param string|int $id guid source id.
*
* @return bool
*
* @throws RuntimeException When source db not supported.
* @throws InvalidArgumentException When id validation fails.
*/
public static function validate(string $db, string|int $id): bool
{
$db = after($db, 'guid_');
$lookup = 'guid_' . $db;
if (false === array_key_exists($lookup, self::SUPPORTED)) {
throw new RuntimeException(
r('Invalid db [{db}] source was given. Expecting [{db_list}].', [
'db' => $db,
'db_list' => implode(', ', array_map(fn($f) => after($f, 'guid_'), array_keys(self::SUPPORTED))),
])
);
}
if (null === (self::VALIDATE_GUID[$lookup] ?? null)) {
return true;
}
if (1 !== preg_match(self::VALIDATE_GUID[$lookup]['pattern'], $id)) {
throw new InvalidArgumentException(
r('Invalid [{value}] value for [{db}]. Expecting [{example}].', [
'db' => $db,
'value' => $id,
'example' => self::VALIDATE_GUID[$lookup]['example'],
])
);
}
return true;
}
/**
* Return suitable pointers to link entity to external id.
*
* @return array
*/
public function getPointers(): array
{
$arr = [];
foreach ($this->data as $key => $value) {
$arr[] = r(self::LOOKUP_KEY, ['db' => $key, 'id' => $value]);
}
return $arr;
}
/**
* Return list of external ids.
*
* @return array
*/
public function getAll(): array
{
return $this->data;
}
/**
* Get Instance of logger.
*
* @return LoggerInterface
*/
private function getLogger(): LoggerInterface
{
if (null === self::$logger) {
self::$logger = Container::get(LoggerInterface::class);
}
return self::$logger;
}
public function jsonSerialize(): mixed
{
return $this->getAll();
}
public function __toString(): string
{
return json_encode($this->getAll());
}
}