55
66use Closure ;
77use Exception ;
8- use Soap \Encoding \Normalizer \PhpPropertyNameNormalizer ;
9- use Soap \Encoding \TypeInference \ComplexTypeBuilder ;
108use Soap \Encoding \TypeInference \XsiTypeDetector ;
119use Soap \Encoding \Xml \Node \Element ;
1210use Soap \Encoding \Xml \Reader \DocumentToLookupArrayReader ;
1513use Soap \Encoding \Xml \Writer \XsdTypeXmlElementWriter ;
1614use Soap \Encoding \Xml \Writer \XsiAttributeBuilder ;
1715use Soap \Engine \Metadata \Model \Property ;
18- use Soap \Engine \Metadata \Model \TypeMeta ;
1916use VeeWee \Reflecta \Iso \Iso ;
2017use VeeWee \Reflecta \Lens \Lens ;
2118use function is_array ;
22- use function Psl \Dict \map ;
2319use function Psl \Dict \map_with_key ;
24- use function Psl \Dict \reindex ;
25- use function Psl \Iter \any ;
26- use function Psl \Vec \sort_by ;
2720use function VeeWee \Reflecta \Iso \object_data ;
28- use function VeeWee \Reflecta \Lens \index ;
29- use function VeeWee \Reflecta \Lens \optional ;
30- use function VeeWee \Reflecta \Lens \property ;
3121use function VeeWee \Xml \Writer \Builder \children as writeChildren ;
3222use function VeeWee \Xml \Writer \Builder \raw ;
3323use function VeeWee \Xml \Writer \Builder \value as buildValue ;
@@ -52,24 +42,24 @@ public function __construct(
5242 */
5343 public function iso (Context $ context ): Iso
5444 {
55- $ properties = $ this -> detectProperties ($ context );
45+ $ objectAccess = ObjectAccess:: forContext ($ context );
5646
5747 return new Iso (
5848 /**
5949 * @param TObj|array $value
6050 * @return non-empty-string
6151 */
62- function (object |array $ value ) use ($ context , $ properties ) : string {
63- return $ this ->to ($ context , $ properties , $ value );
52+ function (object |array $ value ) use ($ context , $ objectAccess ) : string {
53+ return $ this ->to ($ context , $ objectAccess , $ value );
6454 },
6555 /**
6656 * @param non-empty-string|Element $value
6757 * @return TObj
6858 */
69- function (string |Element $ value ) use ($ context , $ properties ) : object {
59+ function (string |Element $ value ) use ($ context , $ objectAccess ) : object {
7060 return $ this ->from (
7161 $ context ,
72- $ properties ,
62+ $ objectAccess ,
7363 ($ value instanceof Element ? $ value : Element::fromString ($ value ))
7464 );
7565 }
@@ -78,19 +68,14 @@ function (string|Element $value) use ($context, $properties) : object {
7868
7969 /**
8070 * @param TObj|array $data
81- * @param array<string, Property> $properties
8271 *
8372 * @return non-empty-string
8473 */
85- private function to (Context $ context , array $ properties , object |array $ data ): string
74+ private function to (Context $ context , ObjectAccess $ objectAccess , object |array $ data ): string
8675 {
8776 if (is_array ($ data )) {
8877 $ data = (object ) $ data ;
8978 }
90- $ isAnyPropertyQualified = any (
91- $ properties ,
92- static fn (Property $ property ): bool => $ property ->getType ()->getMeta ()->isQualified ()->unwrapOr (false )
93- );
9479 $ defaultAction = writeChildren ([]);
9580
9681 return (new XsdTypeXmlElementWriter ())(
@@ -100,32 +85,31 @@ private function to(Context $context, array $properties, object|array $data): st
10085 (new XsiAttributeBuilder (
10186 $ context ,
10287 XsiTypeDetector::detectFromValue ($ context , []),
103- includeXsiTargetNamespace: !$ isAnyPropertyQualified ,
88+ includeXsiTargetNamespace: !$ objectAccess -> isAnyPropertyQualified ,
10489 )),
10590 ...map_with_key (
106- $ properties ,
107- function (string $ normalizePropertyName , Property $ property ) use ($ context , $ data , $ defaultAction ) : Closure {
91+ $ objectAccess -> properties ,
92+ static function (string $ normalizePropertyName , Property $ property ) use ($ objectAccess , $ data , $ defaultAction ) : Closure {
10893 $ type = $ property ->getType ();
10994 $ meta = $ type ->getMeta ();
11095 $ isAttribute = $ meta ->isAttribute ()->unwrapOr (false );
11196
11297 /** @var mixed $value */
113- $ value = $ this ->runLens (
114- property ($ normalizePropertyName ),
115- $ meta ,
116- $ data ,
117- null
98+ $ value = self ::runLens (
99+ $ objectAccess ->encoderLenses [$ normalizePropertyName ],
100+ $ data
118101 );
102+ $ iso = $ objectAccess ->isos [$ normalizePropertyName ];
119103
120104 return match (true ) {
121105 $ isAttribute => $ value ? (new AttributeBuilder (
122106 $ type ,
123- $ this -> grabIsoForProperty ( $ context , $ property ) ->to ($ value )
107+ $ iso ->to ($ value )
124108 ))(...) : $ defaultAction ,
125109 $ property ->getName () === '_ ' => $ value
126- ? buildValue ($ this -> grabIsoForProperty ( $ context , $ property ) ->to ($ value ))
110+ ? buildValue ($ iso ->to ($ value ))
127111 : (new NilAttributeBuilder ())(...),
128- default => $ value ? raw ($ this -> grabIsoForProperty ( $ context , $ property ) ->to ($ value )) : $ defaultAction
112+ default => $ value ? raw ($ iso ->to ($ value )) : $ defaultAction
129113 };
130114 }
131115 )
@@ -135,100 +119,46 @@ function (string $normalizePropertyName, Property $property) use ($context, $dat
135119 }
136120
137121 /**
138- * @param array<string, Property> $properties
139- *
140122 * @return TObj
141123 */
142- private function from (Context $ context , array $ properties , Element $ data ): object
124+ private function from (Context $ context , ObjectAccess $ objectAccess , Element $ data ): object
143125 {
144126 $ nodes = (new DocumentToLookupArrayReader ())($ data );
145127 /** @var Iso<TObj, array<string, mixed>> $objectData */
146128 $ objectData = object_data ($ this ->className );
147129
148130 return $ objectData ->from (
149- map (
150- $ properties ,
151- function (Property $ property ) use ($ context , $ nodes ): mixed {
131+ map_with_key (
132+ $ objectAccess -> properties ,
133+ static function (string $ normalizePropertyName , Property $ property ) use ($ objectAccess , $ nodes ): mixed {
152134 $ type = $ property ->getType ();
153135 $ meta = $ type ->getMeta ();
154136
155137 /** @var string|null $value */
156- $ value = $ this ->runLens (
157- index ($ property ->getName ()),
158- $ meta ,
138+ $ value = self ::runLens (
139+ $ objectAccess ->decoderLenses [$ normalizePropertyName ],
159140 $ nodes ,
160- null
161141 );
142+ $ iso = $ objectAccess ->isos [$ normalizePropertyName ];
162143 $ defaultValue = $ meta ->isList ()->unwrapOr (false ) ? [] : null ;
163144
164145 /** @psalm-suppress PossiblyNullArgument */
165146 return match (true ) {
166- $ meta ->isAttribute ()->unwrapOr (false ) => $ this -> grabIsoForProperty ( $ context , $ property ) ->from ($ value ),
167- default => $ value !== null ? $ this -> grabIsoForProperty ( $ context , $ property ) ->from ($ value ) : $ defaultValue ,
147+ $ meta ->isAttribute ()->unwrapOr (false ) => $ iso ->from ($ value ),
148+ default => $ value !== null ? $ iso ->from ($ value ) : $ defaultValue ,
168149 };
169150 },
170151 )
171152 );
172153 }
173154
174- /**
175- * @return Iso<mixed, string>
176- */
177- private function grabIsoForProperty (Context $ context , Property $ property ): Iso
178- {
179- $ propertyContext = $ context ->withType ($ property ->getType ());
180-
181- return $ context ->registry ->detectEncoderForContext ($ propertyContext )
182- ->iso ($ propertyContext );
183- }
184-
185- private function runLens (Lens $ lens , TypeMeta $ meta , mixed $ data , mixed $ default ): mixed
155+ private static function runLens (Lens $ lens , mixed $ data , mixed $ default = null ): mixed
186156 {
187157 try {
188158 /** @var mixed */
189- return $ this -> decorateLensForType ( $ lens, $ meta ) ->get ($ data );
159+ return $ lens ->get ($ data );
190160 } catch (Exception $ e ) {
191161 return $ default ;
192162 }
193163 }
194-
195- /**
196- * @template S
197- * @template A
198- *
199- * @param Lens<S, A> $lens
200- *
201- * @return Lens<S, A>
202- */
203- private function decorateLensForType (Lens $ lens , TypeMeta $ meta ): Lens
204- {
205- if ($ meta ->isNullable ()->unwrapOr (false )) {
206- return optional ($ lens );
207- }
208-
209- if (
210- $ meta ->isAttribute ()->unwrapOr (false ) &&
211- $ meta ->use ()->unwrapOr ('optional ' ) === 'optional '
212- ) {
213- return optional ($ lens );
214- }
215-
216- return $ lens ;
217- }
218-
219- /**
220- * @return array<string, Property>
221- */
222- private function detectProperties (Context $ context ): array
223- {
224- $ type = ComplexTypeBuilder::default ()($ context );
225-
226- return reindex (
227- sort_by (
228- $ type ->getProperties (),
229- static fn (Property $ property ): bool => !$ property ->getType ()->getMeta ()->isAttribute ()->unwrapOr (false ),
230- ),
231- static fn (Property $ property ): string => PhpPropertyNameNormalizer::normalize ($ property ->getName ()),
232- );
233- }
234164}
0 commit comments