-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathEncoderDetector.php
85 lines (69 loc) · 2.55 KB
/
EncoderDetector.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php
declare(strict_types=1);
namespace Soap\Encoding\Encoder;
use Soap\Engine\Metadata\Model\XsdType;
use stdClass;
use WeakMap;
final class EncoderDetector
{
/**
* @var WeakMap<XsdType, XmlEncoder<mixed, string>>
*/
private WeakMap $cache;
public static function default(): self
{
/** @var self $self */
static $self = new self();
return $self;
}
private function __construct()
{
/** @var WeakMap<XsdType, XmlEncoder<mixed, string>> cache */
$this->cache = new WeakMap();
}
/**
* @return XmlEncoder<mixed, string>
*
* @psalm-suppress InvalidArgument, InvalidReturnType, PossiblyInvalidArgument, InvalidReturnStatement - The simple type detector could return string|null, but should not be an issue here.
*/
public function __invoke(Context $context): XmlEncoder
{
$type = $context->type;
if ($cached = $this->cache[$type] ?? null) {
return $cached;
}
$meta = $type->getMeta();
$encoder = match(true) {
$meta->isSimple()->unwrapOr(false) => SimpleType\EncoderDetector::default()($context),
default => $this->detectComplexTypeEncoder($type, $context),
};
if (!$encoder instanceof Feature\ListAware && $meta->isRepeatingElement()->unwrapOr(false)) {
$encoder = new RepeatingElementEncoder($encoder);
}
if (!$encoder instanceof Feature\OptionalAware && $meta->isNullable()->unwrapOr(false)) {
$encoder = new OptionalElementEncoder($encoder);
}
$encoder = new ErrorHandlingEncoder($encoder);
return $this->cache[$type] = $encoder;
}
/**
* @return XmlEncoder<mixed, string>
*/
private function detectComplexTypeEncoder(XsdType $type, Context $context): XmlEncoder
{
$meta = $type->getMeta();
// Try to find a direct match:
if ($context->registry->hasRegisteredComplexTypeForXsdType($type)) {
return $context->registry->findComplexEncoderByXsdType($type);
}
// Try to find a match for the extended complex type:
// Or fallback to the default object encoder.
return $meta->extends()
->filter(static fn ($extend): bool => !($extend['isSimple'] ?? false))
->map(static fn ($extends) : XmlEncoder => $context->registry->findComplexEncoderByNamespaceName(
$extends['namespace'],
$extends['type'],
))
->unwrapOr(new ObjectEncoder(stdClass::class));
}
}