*/ public readonly array $dictionaryEntries; /** @no-named-arguments */ public function __construct( DictionaryEntry... $dictionaryEntries ) { $this->dictionaryEntries = $dictionaryEntries; } /** * @template T of DictionaryValue|NameValue|Dictionary * @param class-string $valueType * @return T */ public function getValueForKey(DictionaryKey|ExtendedDictionaryKey $dictionaryKey, string $valueType): DictionaryValue|Dictionary|NameValue|null { foreach ($this->dictionaryEntries as $dictionaryEntry) { if (($dictionaryKey instanceof DictionaryKey && $dictionaryEntry->key === $dictionaryKey) || ($dictionaryKey instanceof ExtendedDictionaryKey && $dictionaryEntry->key instanceof ExtendedDictionaryKey && $dictionaryEntry->key->value === $dictionaryKey->value)) { $value = $dictionaryEntry->value; if (is_a($value, $valueType) === false) { throw new InvalidArgumentException(sprintf('Expected value with value %s to be of type %s, got %s', $dictionaryKey->value, $valueType, get_class($value))); } return $value; } } return null; } /** @return class-string */ public function getTypeForKey(DictionaryKey $dictionaryKey): ?string { foreach ($this->dictionaryEntries as $dictionaryEntry) { if ($dictionaryEntry->key === $dictionaryKey) { return $dictionaryEntry->value::class; } } return null; } public function getSubDictionary(?Document $document, DictionaryKey $dictionaryKey): ?Dictionary { $subDictionaryType = $this->getTypeForKey($dictionaryKey); if ($subDictionaryType === null) { return null; } if ($subDictionaryType === Dictionary::class) { return $this->getValueForKey($dictionaryKey, Dictionary::class) ?? throw new RuntimeException(); } if ($subDictionaryType === DictionaryArrayValue::class) { return ($this->getValueForKey($dictionaryKey, DictionaryArrayValue::class) ?? throw new RuntimeException())->toSingleDictionary(); } if ($subDictionaryType === ReferenceValue::class) { if ($document === null) { throw new ParseFailureException('Document is required to get subDictionary for reference'); } return ($this->getObjectForReference($document, $dictionaryKey) ?? throw new ParseFailureException()) ->getDictionary(); } throw new ParseFailureException(sprintf('Invalid type "%s" for subDictionary with key %s', $subDictionaryType, $dictionaryKey->name)); } /** * @template T of DecoratedObject * @param class-string|null $expectedDecoratorFQN * @return ($expectedDecoratorFQN is null ? DecoratedObject : T) */ public function getObjectForReference(Document $document, DictionaryKey|ExtendedDictionaryKey $dictionaryKey, ?string $expectedDecoratorFQN = null): ?DecoratedObject { $reference = $this->getValueForKey($dictionaryKey, ReferenceValue::class); if ($reference === null) { return null; } return $document->getObject($reference->objectNumber, $expectedDecoratorFQN) ?? throw new ParseFailureException(); } /** * @template T of DecoratedObject * @param class-string|null $expectedDecoratorFQN * @return ($expectedDecoratorFQN is null ? list : list) */ public function getObjectsForReference(Document $document, DictionaryKey|ExtendedDictionaryKey $dictionaryKey, ?string $expectedDecoratorFQN = null): array { $references = $this->getValueForKey($dictionaryKey, ReferenceValueArray::class); if ($references === null) { return []; } $objects = []; foreach ($references->referenceValues as $referenceValue) { $objects[] = $document->getObject($referenceValue->objectNumber, $expectedDecoratorFQN) ?? throw new ParseFailureException(); } return $objects; } public function getType(): ?TypeNameValue { if ($this->getTypeForKey(DictionaryKey::TYPE) === Dictionary::class) { return $this->getValueForKey(DictionaryKey::TYPE, Dictionary::class) ?->getValueForKey(DictionaryKey::TYPE, TypeNameValue::class); } return $this->getValueForKey(DictionaryKey::TYPE, TypeNameValue::class); } public function getSubType(): ?SubtypeNameValue { if ($this->getTypeForKey(DictionaryKey::SUBTYPE) === Dictionary::class) { return $this->getValueForKey(DictionaryKey::SUBTYPE, Dictionary::class) ?->getValueForKey(DictionaryKey::SUBTYPE, SubtypeNameValue::class); } return $this->getValueForKey(DictionaryKey::SUBTYPE, SubtypeNameValue::class); } }