@@ -82,18 +82,27 @@ private function __construct(array $schema, array $request_params)
8282
8383 private function getSQLFieldForProperty (string $ prop_name ): string
8484 {
85- $ prop = $ this ->flattened_properties [$ prop_name ];
86- $ is_join = str_contains ($ prop_name , '. ' ) && array_key_exists (explode ('. ' , $ prop_name )[0 ], $ this ->joins );
87- $ sql_field = $ prop ['x-field ' ] ?? $ prop_name ;
85+ $ real_prop_name = str_replace (chr (0x1F ), '. ' , $ prop_name );
86+ $ prop = $ this ->flattened_properties [$ real_prop_name ];
87+ $ is_join = str_contains ($ real_prop_name , '. ' ) && array_key_exists (explode ('. ' , $ real_prop_name )[0 ], $ this ->joins );
88+ $ sql_field = $ prop ['x-field ' ] ?? $ real_prop_name ;
8889 if (!$ is_join ) {
8990 // Only add the _. prefix if it isn't a join
9091 $ sql_field = "_. $ sql_field " ;
91- } else if ($ prop_name !== $ sql_field ) {
92+ } else if ($ real_prop_name !== $ sql_field ) {
9293 // If the property name is different from the SQL field name, we will need to add/change the table alias
9394 // $prop_name is a join where the part before the dot is the join alias (also the property on the main item), and the part after the dot is the property on the joined item
94- $ join_alias = explode ('. ' , $ prop_name )[0 ];
95+ $ parts = explode ('. ' , $ prop_name );
96+ array_pop ($ parts ); // Get rid of the field
97+ $ join_alias = implode ('. ' , $ parts );
9598 $ sql_field = "{$ join_alias }. {$ sql_field }" ;
9699 }
100+ $ parts = explode ('. ' , $ sql_field );
101+ if (count ($ parts ) > 2 ) {
102+ $ field = array_pop ($ parts );
103+ $ table = implode (chr (0x1F ), $ parts );
104+ $ sql_field = "{$ table }. {$ field }" ;
105+ }
97106 return $ sql_field ;
98107 }
99108
@@ -105,6 +114,7 @@ private function getSelectCriteriaForProperty(string $prop_name, bool $distinct_
105114 {
106115 global $ DB ;
107116
117+ $ prop_name = str_replace (chr (0x1F ), '. ' , $ prop_name );
108118 $ prop = $ this ->flattened_properties [$ prop_name ];
109119 if ($ prop ['x-writeonly ' ] ?? false ) {
110120 // Do not expose write-only fields
@@ -164,6 +174,7 @@ private static function getJoins(string $join_alias, array $join_definition): ar
164174 if (!isset ($ joins [$ join_type ])) {
165175 $ joins [$ join_type ] = [];
166176 }
177+ $ join_alias = str_replace ('. ' , chr (0x1F ), $ join_alias );
167178 $ join_table = $ join ['table ' ] . ' AS ' . $ join_alias ;
168179 $ join_parent = (isset ($ join ['ref_join ' ]) && $ join ['ref_join ' ]) ? "{$ join_alias }_ref " : '_ ' ;
169180 if (isset ($ join ['ref_join ' ])) {
@@ -390,6 +401,7 @@ private function getMatchingRecords($ignore_pagination = false): array
390401 $ criteria ['GROUPBY ' ] = ['_itemtype ' , '_.id ' ];
391402 } else {
392403 foreach ($ this ->joins as $ join_alias => $ join ) {
404+ $ join_alias = str_replace ('. ' , chr (0x1F ), $ join_alias );
393405 $ s = $ this ->getSelectCriteriaForProperty ("$ join_alias.id " , true );
394406 if ($ s !== null ) {
395407 $ criteria ['SELECT ' ][] = $ s ;
@@ -495,6 +507,11 @@ private function hydrateRecords(array $records): array
495507 }
496508 } else {
497509 foreach ($ this ->joins as $ join_alias => $ join ) {
510+ $ parts = explode (chr (0x1F ), $ fkey );
511+ if (count ($ parts ) > 1 ) {
512+ $ field = array_pop ($ parts );
513+ $ fkey = implode ('. ' , $ parts ) . chr (0x1F ) . $ field ;
514+ }
498515 if ($ fkey === $ join_alias . chr (0x1F ) . 'id ' ) {
499516 $ fkey_tables [$ fkey ] = $ join ['table ' ];
500517 break ;
@@ -543,17 +560,20 @@ private function hydrateRecords(array $records): array
543560 $ criteria ['SELECT ' ][] = new QueryExpression ($ DB ::quoteValue ($ schema_name ), '_itemtype ' );
544561 }
545562 } else {
546- $ join_name = explode (chr (0x1F ), $ fkey )[0 ];
547- $ props_to_use = array_filter ($ this ->flattened_properties , static function ($ prop_name ) use ($ join_name ) {
548- return str_starts_with ($ prop_name , $ join_name . '. ' );
563+ $ join_name_parts = explode (chr (0x1F ), $ fkey );
564+ array_pop ($ join_name_parts );
565+ $ join_name = implode (chr (0x1F ), $ join_name_parts );
566+ $ join_name_dotted = str_replace (chr (0x1F ), '. ' , $ join_name );
567+ $ props_to_use = array_filter ($ this ->flattened_properties , static function ($ prop_name ) use ($ join_name_dotted ) {
568+ return str_starts_with ($ prop_name , $ join_name_dotted . '. ' );
549569 }, ARRAY_FILTER_USE_KEY );
550570
551571 $ criteria ['FROM ' ] = "$ table AS " . $ DB ::quoteName ($ join_name );
552572 $ id_field = $ join_name . '.id ' ;
553573 }
554574 $ criteria ['WHERE ' ] = [$ id_field => $ ids_to_fetch ];
555575 foreach ($ props_to_use as $ prop_name => $ prop ) {
556- if ($ prop ['x-writeonly ' ] ?? false ) {
576+ if ($ prop ['x-writeonly ' ] ?? false || isset ( $ prop [ ' x-mapped-from ' ]) ) {
557577 continue ;
558578 }
559579 $ sql_field = $ this ->getSQLFieldForProperty ($ prop_name );
0 commit comments