mirror of
https://github.com/werkraum-media/thuecat.git
synced 2024-11-15 01:36:11 +01:00
249 lines
6.6 KiB
PHP
249 lines
6.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
namespace WerkraumMedia\ThueCat\Domain\Import\EntityMapper;
|
|
|
|
use InvalidArgumentException;
|
|
use function str_starts_with;
|
|
use Symfony\Component\Serializer\Encoder\JsonDecode as SymfonyJsonDecode;
|
|
|
|
/**
|
|
* Used to add further necessary normalization on decoding incoming JSON structure.
|
|
*
|
|
* See list of decode* methods to see what kind of data is normalized.
|
|
*/
|
|
class JsonDecode extends SymfonyJsonDecode
|
|
{
|
|
public const ACTIVE_LANGUAGE = 'active_language';
|
|
|
|
/**
|
|
* @var array[]
|
|
*/
|
|
private $rulesToKeepTypeInfo = [
|
|
[
|
|
'type' => 'beginsWith',
|
|
'comparisonValue' => 'thuecat:facilityAccessibility',
|
|
],
|
|
];
|
|
|
|
public function decode(
|
|
string $data,
|
|
string $format,
|
|
array $context = []
|
|
): mixed {
|
|
$context[self::ASSOCIATIVE] = true;
|
|
$result = parent::decode($data, $format, $context);
|
|
|
|
$activeLanguage = $context[self::ACTIVE_LANGUAGE] ?? '';
|
|
if ($activeLanguage === '') {
|
|
throw new InvalidArgumentException('Provide active language: ' . self::ACTIVE_LANGUAGE);
|
|
}
|
|
|
|
return $this->process(
|
|
$result,
|
|
$activeLanguage
|
|
);
|
|
}
|
|
|
|
private function process(
|
|
array &$array,
|
|
string $activeLanguage
|
|
): array {
|
|
foreach ($array as $key => $value) {
|
|
$value = $this->decodeDateTime($value);
|
|
$value = $this->decodeSingleValues($value);
|
|
$value = $this->decodeLanguageSpecificValue($value, $activeLanguage);
|
|
|
|
if (is_array($value)) {
|
|
$value = $this->process($value, $activeLanguage);
|
|
}
|
|
|
|
$newKey = $this->mapKey($key);
|
|
if ($newKey !== $key) {
|
|
unset($array[$key]);
|
|
}
|
|
$array[$newKey] = $value;
|
|
}
|
|
|
|
return $array;
|
|
}
|
|
|
|
/**
|
|
* Some properties might contain a list of value where each list entry is for a specific language.
|
|
*
|
|
* This decode will resolve the list to a single value based on current language settings from context.
|
|
*
|
|
* @param mixed $value
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function decodeLanguageSpecificValue(
|
|
&$value,
|
|
string $activeLanguage
|
|
) {
|
|
if (is_array($value) === false) {
|
|
return $value;
|
|
}
|
|
|
|
$newValue = $value['@value'] ?? null;
|
|
$language = $value['@language'] ?? null;
|
|
if (is_string($newValue) && $language === $activeLanguage) {
|
|
return $newValue;
|
|
}
|
|
if (is_string($newValue) && is_string($language) && $language !== $activeLanguage) {
|
|
return '';
|
|
}
|
|
|
|
$hasLanguageValue = false;
|
|
if (ArrayDenormalizer::hasOnlyNumericKeys($value) === false) {
|
|
return $value;
|
|
}
|
|
|
|
foreach ($value as $languageSpecific) {
|
|
if (is_array($languageSpecific) === false) {
|
|
continue;
|
|
}
|
|
|
|
$language = $languageSpecific['@language'] ?? '';
|
|
if ($language === '') {
|
|
continue;
|
|
}
|
|
|
|
if ($language === $activeLanguage) {
|
|
$newValue = $languageSpecific['@value'] ?? null;
|
|
}
|
|
if (is_string($newValue)) {
|
|
return $newValue;
|
|
}
|
|
|
|
if ($hasLanguageValue === false && isset($languageSpecific['@value'])) {
|
|
$hasLanguageValue = true;
|
|
}
|
|
}
|
|
|
|
// Prevent delivering original array if we detected this is language specific.
|
|
// A string is then expected. But we didn't find any, so return empty one to conform to type.
|
|
if ($hasLanguageValue) {
|
|
return '';
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Some properties might be an array with extra info.
|
|
*
|
|
* This decode will resolve single values wrapped in array with extra info.
|
|
*
|
|
* @param mixed $value
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function decodeSingleValues(
|
|
&$value
|
|
) {
|
|
if (is_array($value) === false) {
|
|
return $value;
|
|
}
|
|
|
|
if (array_key_exists('@language', $value)) {
|
|
return $value;
|
|
}
|
|
|
|
$type = $value['@type'] ?? null;
|
|
if (is_string($type)) {
|
|
foreach ($this->rulesToKeepTypeInfo as $rule) {
|
|
if ($this->doesRuleMatch($rule, $type)) {
|
|
return $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
$newValue = $value['@value'] ?? null;
|
|
if (is_string($newValue)) {
|
|
return $newValue;
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Prepare data structure for PHP \DateTimeImmutable.
|
|
*
|
|
* @param mixed $value
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function decodeDateTime(
|
|
&$value
|
|
) {
|
|
$supportedTypes = [
|
|
'schema:Time',
|
|
'schema:Date',
|
|
];
|
|
|
|
if (
|
|
is_array($value) === false
|
|
|| isset($value['@type']) === false
|
|
|| isset($value['@value']) === false
|
|
|| in_array($value['@type'], $supportedTypes) === false
|
|
) {
|
|
return $value;
|
|
}
|
|
|
|
return $value['@value'];
|
|
}
|
|
|
|
/**
|
|
* @param mixed $key
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function mapKey($key)
|
|
{
|
|
if (is_string($key) === false) {
|
|
return $key;
|
|
}
|
|
|
|
if (str_starts_with($key, '@')) {
|
|
return mb_substr($key, 1);
|
|
}
|
|
if (str_starts_with($key, 'schema:')) {
|
|
return mb_substr($key, 7);
|
|
}
|
|
if (str_starts_with($key, 'thuecat:')) {
|
|
return mb_substr($key, 8);
|
|
}
|
|
|
|
return $key;
|
|
}
|
|
|
|
private function doesRuleMatch(array $rule, string $type): bool
|
|
{
|
|
if ($rule['type'] === 'beginsWith') {
|
|
return str_starts_with($type, $rule['comparisonValue']);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|