1111use TypeLang \Mapper \Exception \Mapping \RuntimeException ;
1212use TypeLang \Mapper \Mapping \Metadata \ClassMetadata ;
1313use TypeLang \Mapper \Mapping \Metadata \DiscriminatorMapMetadata ;
14+ use TypeLang \Mapper \Mapping \Metadata \PropertyMetadata ;
1415use TypeLang \Mapper \Runtime \Context ;
1516use TypeLang \Mapper \Runtime \Path \Entry \ObjectEntry ;
1617use TypeLang \Mapper \Runtime \Path \Entry \ObjectPropertyEntry ;
@@ -34,7 +35,56 @@ public function __construct(
3435
3536 public function match (mixed $ value , Context $ context ): bool
3637 {
37- return \is_object ($ value ) || \is_array ($ value );
38+ return (\is_array ($ value ) || \is_object ($ value ))
39+ && $ this ->matchRequiredProperties ((array ) $ value , $ context );
40+ }
41+
42+ /**
43+ * @throws \Throwable
44+ */
45+ private function getPropertyType (PropertyMetadata $ meta , Context $ context ): TypeInterface
46+ {
47+ // Fetch field type
48+ $ info = $ meta ->findTypeInfo ();
49+
50+ if ($ info === null ) {
51+ return $ context ->getTypeByDefinition ('mixed ' );
52+ }
53+
54+ return $ info ->getType ();
55+ }
56+
57+ /**
58+ * @param array<array-key, mixed> $payload
59+ */
60+ private function matchRequiredProperties (array $ payload , Context $ context ): bool
61+ {
62+ foreach ($ this ->metadata ->getProperties () as $ meta ) {
63+ // Match property for existence
64+ if (!\array_key_exists ($ meta ->getExportName (), $ payload )) {
65+ // Skip all properties with defaults
66+ if ($ meta ->hasDefaultValue ()) {
67+ continue ;
68+ }
69+
70+ return false ;
71+ }
72+
73+ // Fetch field value and type
74+ try {
75+ $ value = $ payload [$ meta ->getExportName ()];
76+ $ type = $ this ->getPropertyType ($ meta , $ context );
77+ } catch (\Throwable ) {
78+ return false ;
79+ }
80+
81+ // Assert valid type
82+ if (!$ type ->match ($ value , $ context )) {
83+ return false ;
84+ }
85+ }
86+
87+ return true ;
3888 }
3989
4090 /**
@@ -165,10 +215,7 @@ private function denormalizeObject(array $value, object $object, Context $contex
165215 // In case of value has been passed
166216 case \array_key_exists ($ meta ->getExportName (), $ value ):
167217 $ element = $ value [$ meta ->getExportName ()];
168-
169- // Fetch field type
170- $ info = $ meta ->findTypeInfo ();
171- $ type = $ info !== null ? $ info ->getType () : $ context ->getTypeByDefinition ('mixed ' );
218+ $ type = $ this ->getPropertyType ($ meta , $ context );
172219
173220 try {
174221 $ element = $ type ->cast ($ element , $ entrance );
0 commit comments