2222use ONGR \ElasticsearchBundle \Annotation \ObjectType ;
2323use ONGR \ElasticsearchBundle \Annotation \PropertiesAwareInterface ;
2424use ONGR \ElasticsearchBundle \Annotation \Property ;
25- use ONGR \ElasticsearchBundle \DependencyInjection \Configuration ;
2625
2726/**
2827 * Document parser used for reading document annotations.
2928 */
3029class DocumentParser
3130{
32- const OBJ_CACHED_FIELDS = 'ongr.obj_fields ' ;
33- const EMBEDDED_CACHED_FIELDS = 'ongr.embedded_fields ' ;
34- const ARRAY_CACHED_FIELDS = 'ongr.array_fields ' ;
3531
3632 private $ reader ;
3733 private $ properties = [];
34+ private $ methods = [];
3835 private $ analysisConfig = [];
3936 private $ cache ;
4037
@@ -106,36 +103,14 @@ private function getClassMetadata(\ReflectionClass $class): array
106103 /** @var \ReflectionProperty $property */
107104 foreach ($ this ->getDocumentPropertiesReflection ($ class ) as $ name => $ property ) {
108105 $ annotations = $ this ->reader ->getPropertyAnnotations ($ property );
106+ $ this ->getPropertyMapping ($ annotations , $ embeddedFields , $ name , $ mapping , $ objFields , $ arrayFields );
107+ }
109108
110- /** @var AbstractAnnotation $annotation */
111- foreach ($ annotations as $ annotation ) {
112- if (!$ annotation instanceof PropertiesAwareInterface) {
113- continue ;
114- }
115-
116- $ fieldMapping = $ annotation ->getSettings ();
117-
118- if ($ annotation instanceof Property) {
119- $ fieldMapping ['type ' ] = $ annotation ->type ;
120- if ($ annotation ->fields ) {
121- $ fieldMapping ['fields ' ] = $ annotation ->fields ;
122- }
123- $ fieldMapping ['analyzer ' ] = $ annotation ->analyzer ;
124- $ fieldMapping ['search_analyzer ' ] = $ annotation ->searchAnalyzer ;
125- $ fieldMapping ['search_quote_analyzer ' ] = $ annotation ->searchQuoteAnalyzer ;
126- }
127-
128- if ($ annotation instanceof Embedded) {
129- $ embeddedClass = new \ReflectionClass ($ annotation ->class );
130- $ fieldMapping ['type ' ] = $ this ->getObjectMappingType ($ embeddedClass );
131- $ fieldMapping ['properties ' ] = $ this ->getClassMetadata ($ embeddedClass );
132- $ embeddedFields [$ name ] = $ annotation ->class ;
133- }
134-
135- $ mapping [$ annotation ->getName () ?? Caser::snake ($ name )] = array_filter ($ fieldMapping );
136- $ objFields [$ name ] = $ annotation ->getName () ?? Caser::snake ($ name );
137- $ arrayFields [$ annotation ->getName () ?? Caser::snake ($ name )] = $ name ;
138- }
109+ /** @var \ReflectionMethod $method */
110+ foreach ($ this ->getDocumentMethodsReflection ($ class ) as $ name => $ method ) {
111+ $ name = $ this ->guessPropertyNameFromGetter ($ name );
112+ $ annotations = $ this ->reader ->getMethodAnnotations ($ method );
113+ $ this ->getPropertyMapping ($ annotations , $ embeddedFields , $ name , $ mapping , $ objFields , $ arrayFields );
139114 }
140115
141116 //Embeded fields are option compared to the array or object mapping.
@@ -164,10 +139,10 @@ public function getPropertyMetadata(\ReflectionClass $class, bool $subClass = fa
164139
165140 $ metadata = [];
166141
167- /** @var \ReflectionProperty $property */
168- foreach ($ this ->getDocumentPropertiesReflection ($ class ) as $ name => $ property ) {
142+ /** @var \ReflectionProperty $method */
143+ foreach ($ this ->getDocumentPropertiesReflection ($ class ) as $ name => $ method ) {
169144 /** @var AbstractAnnotation $annotation */
170- foreach ($ this ->reader ->getPropertyAnnotations ($ property ) as $ annotation ) {
145+ foreach ($ this ->reader ->getPropertyAnnotations ($ method ) as $ annotation ) {
171146 if (!$ annotation instanceof PropertiesAwareInterface) {
172147 continue ;
173148 }
@@ -177,13 +152,13 @@ public function getPropertyMetadata(\ReflectionClass $class, bool $subClass = fa
177152 'class ' => null ,
178153 'embeded ' => false ,
179154 'type ' => null ,
180- 'public ' => $ property ->isPublic (),
155+ 'public ' => $ method ->isPublic (),
181156 'getter ' => null ,
182157 'setter ' => null ,
183158 'sub_properties ' => []
184159 ];
185160
186- $ name = $ property ->getName ();
161+ $ name = $ method ->getName ();
187162 $ propertyMetadata ['name ' ] = $ name ;
188163
189164 if (!$ propertyMetadata ['public ' ]) {
@@ -217,6 +192,52 @@ public function getPropertyMetadata(\ReflectionClass $class, bool $subClass = fa
217192 }
218193 }
219194
195+ /** @var \ReflectionProperty $property */
196+ foreach ($ this ->getDocumentMethodsReflection ($ class ) as $ name => $ method ) {
197+ /** @var AbstractAnnotation $annotation */
198+ foreach ($ this ->reader ->getMethodAnnotations ($ method ) as $ annotation ) {
199+ if (!$ annotation instanceof PropertiesAwareInterface) {
200+ continue ;
201+ }
202+
203+ $ guessedName = $ this ->guessPropertyNameFromGetter ($ name );
204+ $ fieldName = $ annotation ->getName () ?? Caser::snake ($ guessedName );
205+
206+ $ propertyMetadata = [
207+ 'identifier ' => false ,
208+ 'class ' => null ,
209+ 'embeded ' => false ,
210+ 'type ' => null ,
211+ 'public ' => false ,
212+ 'getter ' => $ name ,
213+ 'setter ' => null ,
214+ 'sub_properties ' => [],
215+ 'name ' => $ annotation ->getName () ?? $ guessedName
216+ ];
217+
218+ if ($ annotation instanceof Id) {
219+ $ propertyMetadata ['identifier ' ] = true ;
220+ }
221+
222+ if ($ annotation instanceof Property) {
223+ // we need the type (and possibly settings?) in Converter::denormalize()
224+ $ propertyMetadata ['type ' ] = $ annotation ->type ;
225+ $ propertyMetadata ['settings ' ] = $ annotation ->settings ;
226+ }
227+
228+ if ($ annotation instanceof Embedded) {
229+ $ propertyMetadata ['embeded ' ] = true ;
230+ $ propertyMetadata ['class ' ] = $ annotation ->class ;
231+ $ propertyMetadata ['sub_properties ' ] = $ this ->getPropertyMetadata (
232+ new \ReflectionClass ($ annotation ->class ),
233+ true
234+ );
235+ }
236+
237+ $ metadata [$ fieldName ] = $ propertyMetadata ;
238+ }
239+ }
240+
220241 return $ metadata ;
221242 }
222243
@@ -284,6 +305,15 @@ protected function guessGetter(\ReflectionClass $class, $name): string
284305 throw new \Exception ("Could not determine a getter for ` $ name` of class ` {$ class ->getNamespaceName ()}` " );
285306 }
286307
308+ protected function guessPropertyNameFromGetter ($ name ): string
309+ {
310+ if (preg_match ('/^get([A-Z_0-9].*?)$/ ' , $ name , $ matches )) {
311+ return lcfirst ($ matches [1 ]);
312+ }
313+
314+ return $ name ;
315+ }
316+
287317 protected function guessSetter (\ReflectionClass $ class , $ name ): string
288318 {
289319 if ($ class ->hasMethod ('set ' . ucfirst ($ name ))) {
@@ -356,6 +386,13 @@ private function getDocumentPropertiesReflection(\ReflectionClass $class): array
356386 }
357387 }
358388
389+ foreach ($ class ->getMethods () as $ method ) {
390+
391+ if (!in_array ($ property ->getName (), $ properties )) {
392+ $ properties [$ property ->getName ()] = $ property ;
393+ }
394+ }
395+
359396 $ parentReflection = $ class ->getParentClass ();
360397 if ($ parentReflection !== false ) {
361398 $ properties = array_merge (
@@ -368,4 +405,74 @@ private function getDocumentPropertiesReflection(\ReflectionClass $class): array
368405
369406 return $ properties ;
370407 }
408+
409+ private function getDocumentMethodsReflection (\ReflectionClass $ class ): array
410+ {
411+ if (in_array ($ class ->getName (), $ this ->methods )) {
412+ return $ this ->methods [$ class ->getName ()];
413+ }
414+
415+ $ methods = [];
416+
417+ foreach ($ class ->getMethods () as $ method ) {
418+ if (!in_array ($ method ->getName (), $ methods )) {
419+ $ methods [$ method ->getName ()] = $ method ;
420+ }
421+ }
422+
423+ $ parentReflection = $ class ->getParentClass ();
424+ if ($ parentReflection !== false ) {
425+ $ methods = array_merge (
426+ $ methods ,
427+ array_diff_key ($ this ->getDocumentMethodsReflection ($ parentReflection ), $ methods )
428+ );
429+ }
430+
431+ $ this ->methods [$ class ->getName ()] = $ methods ;
432+
433+ return $ methods ;
434+ }
435+
436+ /**
437+ * @param array $annotations
438+ * @param $embeddedFields
439+ * @param string $name
440+ * @param array $mapping
441+ * @param array $objFields
442+ * @param array $arrayFields
443+ * @throws \ReflectionException
444+ */
445+ private function getPropertyMapping (array $ annotations , &$ embeddedFields , string $ name , array &$ mapping , ?array &$ objFields , ?array &$ arrayFields ): void
446+ {
447+ /** @var AbstractAnnotation $annotation */
448+ foreach ($ annotations as $ annotation ) {
449+ if (!$ annotation instanceof PropertiesAwareInterface) {
450+ continue ;
451+ }
452+
453+ $ fieldMapping = $ annotation ->getSettings ();
454+
455+ if ($ annotation instanceof Property) {
456+ $ fieldMapping ['type ' ] = $ annotation ->type ;
457+ if ($ annotation ->fields ) {
458+ $ fieldMapping ['fields ' ] = $ annotation ->fields ;
459+ }
460+ $ fieldMapping ['analyzer ' ] = $ annotation ->analyzer ;
461+ $ fieldMapping ['search_analyzer ' ] = $ annotation ->searchAnalyzer ;
462+ $ fieldMapping ['search_quote_analyzer ' ] = $ annotation ->searchQuoteAnalyzer ;
463+ }
464+
465+ if ($ annotation instanceof Embedded) {
466+ $ embeddedClass = new \ReflectionClass ($ annotation ->class );
467+ $ fieldMapping ['type ' ] = $ this ->getObjectMappingType ($ embeddedClass );
468+ $ fieldMapping ['properties ' ] = $ this ->getClassMetadata ($ embeddedClass );
469+ $ embeddedFields [$ name ] = $ annotation ->class ;
470+ }
471+
472+ $ fieldName = $ annotation ->getName () ?? Caser::snake ($ name );
473+ $ mapping [$ fieldName ] = array_filter ($ fieldMapping );
474+ $ objFields [$ name ] = $ fieldName ;
475+ $ arrayFields [$ fieldName ] = $ name ;
476+ }
477+ }
371478}
0 commit comments