Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
Structs
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
8 / 8
16
100.00% covered (success)
100.00%
1 / 1
 parse
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 parseType
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 parseComplexStruct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 parseUnionStruct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 cleanType
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 isStructDefined
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 structHasBeenDefined
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 typeSignature
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace WsdlToPhp\PackageGenerator\Parser\SoapClient;
6
7final class Structs extends AbstractParser
8{
9    public const STRUCT_DECLARATION = 'struct';
10    public const UNION_DECLARATION = 'union';
11    public const ANY_XML_DECLARATION = '<anyXML>';
12    public const ANY_XML_TYPE = \DOMDocument::class;
13
14    protected array $definedStructs = [];
15
16    public function parse(): void
17    {
18        $types = $this
19            ->getGenerator()
20            ->getSoapClient()
21            ->getSoapClient()
22            ->getSoapClient()
23            ->__getTypes()
24        ;
25
26        foreach ($types as $type) {
27            $this->parseType($type);
28        }
29    }
30
31    protected function parseType(string $type): void
32    {
33        if ($this->isStructDefined($type)) {
34            return;
35        }
36
37        $cleanType = self::cleanType($type);
38        $typeDef = explode(' ', $cleanType);
39
40        if (array_key_exists(1, $typeDef)) {
41            $structName = $typeDef[1];
42            if (self::UNION_DECLARATION === $typeDef[0]) {
43                $this->parseUnionStruct($typeDef);
44            } elseif (self::STRUCT_DECLARATION === $typeDef[0]) {
45                $this->parseComplexStruct($typeDef);
46            } else {
47                $this->getGenerator()->getStructs()->addVirtualStruct($structName, $typeDef[0]);
48            }
49        }
50
51        $this->structHasBeenDefined($type);
52    }
53
54    protected function parseComplexStruct(array $typeDef): void
55    {
56        $typeDefCount = count($typeDef);
57        if (3 < $typeDefCount) {
58            for ($i = 2; $i < $typeDefCount; $i += 2) {
59                $structParamType = str_replace(self::ANY_XML_DECLARATION, self::ANY_XML_TYPE, $typeDef[$i]);
60                $structParamName = $typeDef[$i + 1];
61                $this->getGenerator()->getStructs()->addStructWithAttribute($typeDef[1], $structParamName, $structParamType);
62            }
63        } else {
64            $this->getGenerator()->getStructs()->addStruct($typeDef[1]);
65        }
66    }
67
68    /**
69     * union types are passed such as ",dateTime,time" or ",PMS_ResStatusType,TransactionActionType,UpperCaseAlphaLength1to2".
70     */
71    protected function parseUnionStruct(array $typeDef): void
72    {
73        $typeDefCount = count($typeDef);
74        if (3 === $typeDefCount) {
75            $unionName = $typeDef[1];
76            $unionTypes = array_filter(explode(',', $typeDef[2]), fn ($type) => !empty($type));
77            sort($unionTypes);
78            $this->getGenerator()->getStructs()->addUnionStruct($unionName, $unionTypes);
79        }
80    }
81
82    /**
83     * Remove useless break line, tabs
84     * Remove curly braces
85     * Remove brackets
86     * Adds space before semicolon to parse it
87     * Remove duplicated spaces.
88     */
89    protected static function cleanType(string $type): string
90    {
91        $type = str_replace([
92            "\r",
93            "\n",
94            "\t",
95            '{',
96            '}',
97            '[',
98            ']',
99            ';',
100        ], '', $type);
101        $type = preg_replace('/[\s]+/', ' ', $type);
102
103        return trim($type);
104    }
105
106    protected function isStructDefined(string $type): bool
107    {
108        return in_array(self::typeSignature($type), $this->definedStructs);
109    }
110
111    protected function structHasBeenDefined(string $type): Structs
112    {
113        $this->definedStructs[] = self::typeSignature($type);
114
115        return $this;
116    }
117
118    protected static function typeSignature(string $type): string
119    {
120        return md5($type);
121    }
122}