66
77class AvscToJson implements ConverterInterface
88{
9+ /** @var array<string,mixed> $options */
910 private array $ options ;
1011
12+ /**
13+ * @param string $avscSchema
14+ * @param array<string,mixed> $options
15+ * @return string
16+ */
1117 public function convert (string $ avscSchema , array $ options ): string
1218 {
1319 $ this ->options = $ options ;
14- $ avscArray = json_decode ($ avscSchema , true );
20+
21+ /** @var mixed[] $avscArray */
22+ $ avscArray = json_decode ($ avscSchema , true , JSON_THROW_ON_ERROR );
1523 $ jsonArray = $ this ->convertAvro ($ avscArray );
24+
25+ /** @var string $rawJson */
1626 $ rawJson = json_encode ($ jsonArray );
1727 $ json = $ this ->fixAvroTypes ($ rawJson );
1828
1929 return $ json ;
2030 }
2131
32+ /**
33+ * @param mixed[] $avscArray
34+ * @return mixed[]
35+ */
2236 private function convertAvro (array $ avscArray ): array
2337 {
2438 $ jsonArray = [];
@@ -30,21 +44,28 @@ private function convertAvro(array $avscArray): array
3044 if ('type ' === $ key && 'array ' === $ value ) {
3145 $ jsonArray [$ key ] = $ value ;
3246
47+ /** @var string|mixed[] $items */
48+ $ items = $ avscArray ['items ' ];
49+
3350 if (
34- true === $ this ->isBasicType ($ avscArray ['items ' ])
35- || (true === is_array ($ avscArray ['items ' ]) && true === $ this ->isBasicTypeArray ($ avscArray ['items ' ]))
51+ true === $ this ->isBasicType ($ items )
52+ || (true === is_array ($ items ) && true === $ this ->isBasicTypeArray ($ items ))
53+ ) {
54+ $ jsonArray ['items ' ] = $ items ;
55+ } elseif (
56+ true === is_array ($ items )
57+ && true === isset ($ items ['type ' ])
58+ && 'record ' === $ items ['type ' ]
3659 ) {
37- $ jsonArray ['items ' ] = $ avscArray ['items ' ];
38- } elseif (true === isset ($ avscArray ['items ' ]['type ' ]) && 'record ' === $ avscArray ['items ' ]['type ' ]) {
39- $ jsonArray ['items ' ] = $ this ->convertAvro ($ avscArray ['items ' ]);
40- } else {
41- $ jsonArray ['items ' ] = $ this ->getAnyOf ($ avscArray ['items ' ]);
60+ $ jsonArray ['items ' ] = $ this ->convertAvro ($ items );
61+ } elseif (true === is_array ($ items )) {
62+ $ jsonArray ['items ' ] = $ this ->getAnyOf ($ items );
4263 }
4364 }
44- if ('name ' === $ key ) {
65+ if ('name ' === $ key && true === is_string ( $ value ) ) {
4566 $ jsonArray ['title ' ] = $ this ->snakeToPascal ($ value );
4667 }
47- if ('fields ' === $ key ) {
68+ if ('fields ' === $ key && true === is_array ( $ value ) ) {
4869 $ jsonArray ['properties ' ] = $ this ->convertAvroFieldsToJsonFields ($ value );
4970 $ requiredFields = $ this ->getRequiredFields ($ value );
5071
@@ -57,11 +78,16 @@ private function convertAvro(array $avscArray): array
5778 return $ jsonArray ;
5879 }
5980
81+ /**
82+ * @param mixed[] $avroFields
83+ * @return mixed[]
84+ */
6085 private function convertAvroFieldsToJsonFields (array $ avroFields ): array
6186 {
6287 $ fields = [];
6388
6489 foreach ($ avroFields as $ field ) {
90+ /** @var string|mixed[] $fieldType */
6591 $ fieldType = $ field ['type ' ];
6692
6793 if (
@@ -80,13 +106,19 @@ private function convertAvroFieldsToJsonFields(array $avroFields): array
80106 return $ fields ;
81107 }
82108
109+ /**
110+ * @param mixed[] $avroFields
111+ * @return mixed[]
112+ */
83113 private function getRequiredFields (array $ avroFields ): array
84114 {
85115 $ requiredFields = [];
86116
87117 foreach ($ avroFields as $ field ) {
88118 if (
89- true === $ this ->options ['markNoDefaultAsRequired ' ] && false === array_key_exists ('default ' , $ field )
119+ true === $ this ->options ['markNoDefaultAsRequired ' ]
120+ && true === is_array ($ field )
121+ && false === array_key_exists ('default ' , $ field )
90122 ) {
91123 $ requiredFields [] = $ field ['name ' ];
92124 } elseif (false === $ this ->options ['markNoDefaultAsRequired ' ]) {
@@ -97,17 +129,28 @@ private function getRequiredFields(array $avroFields): array
97129 return $ requiredFields ;
98130 }
99131
132+ /**
133+ * @param mixed[] $types
134+ * @return mixed[]
135+ */
100136 private function getAnyOf (array $ types )
101137 {
102138 $ anyOf = [];
103139
104140 foreach ($ types as $ type ) {
141+ if (false === is_string ($ type ) && false === is_array ($ type )) {
142+ continue ;
143+ }
105144 $ anyOf ['anyOf ' ][] = $ this ->getAnyOfType ($ type );
106145 }
107146
108147 return $ anyOf ;
109148 }
110149
150+ /**
151+ * @param string|mixed[] $type
152+ * @return mixed[]|string[]
153+ */
111154 private function getAnyOfType ($ type )
112155 {
113156 if (true === is_string ($ type )) {
@@ -117,9 +160,16 @@ private function getAnyOfType($type)
117160 }
118161 }
119162
163+ /**
164+ * @param mixed[] $fieldTypes
165+ * @return bool
166+ */
120167 private function isBasicTypeArray (array $ fieldTypes ): bool
121168 {
122169 foreach ($ fieldTypes as $ type ) {
170+ if (false === is_string ($ type ) && false === is_array ($ type )) {
171+ continue ;
172+ }
123173 if (false === $ this ->isBasicType ($ type )) {
124174 return false ;
125175 }
@@ -128,6 +178,10 @@ private function isBasicTypeArray(array $fieldTypes): bool
128178 return true ;
129179 }
130180
181+ /**
182+ * @param string|mixed[] $type
183+ * @return bool
184+ */
131185 private function isBasicType ($ type )
132186 {
133187 if (false === is_string ($ type )) {
@@ -142,13 +196,14 @@ private function snakeToPascal(string $input): string
142196 return str_replace (' ' , '' , ucwords (str_replace ('_ ' , ' ' , $ input )));
143197 }
144198
145- private function fixAvroTypes (string $ rawJson )
199+ private function fixAvroTypes (string $ rawJson ): string
146200 {
147201 $ json = str_replace ('int ' , 'integer ' , $ rawJson );
148202 $ json = str_replace ('long ' , 'number ' , $ json );
149203 $ json = str_replace ('float ' , 'number ' , $ json );
150204 $ json = str_replace ('double ' , 'number ' , $ json );
151205 $ json = str_replace ('bytes ' , 'string ' , $ json );
206+
152207 return $ json ;
153208 }
154209}
0 commit comments