@@ -4996,8 +4996,8 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
49964996
49974997    protected  function  preSaveRelatedRecords (<AdapterInterface> connection, related, <CollectionInterface> visited ) ->  bool
49984998    {
4999-         var  className, manager, type, relation, columns, referencedFields, nesting, name, record;
5000- 
4999+         var  className, manager, type, relation, columns, referencedFields, nesting, name, record, columnA, columnB ;
5000+          int  columnCount, i; 
50015001        let  nesting =  false ;
50025002
50035003        /** 
@@ -5034,17 +5034,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
50345034                            " Only objects can be stored as part of belongs-to relations in '"   . get_class(this ) . " ' Relation "   . name
50355035                        );
50365036                    }
5037-                     let  columns =  relation-> getFields(),
5038-                         referencedFields =  relation-> getReferencedFields();
5039- //                     let columns = relation->getFields(),
5040- //                         referencedModel = relation->getReferencedModel(),
5041- //                         referencedFields = relation->getReferencedFields();
5042- 
5043-                     if  unlikely  typeof  columns ===  " array"   {
5044-                         connection-> rollback(nesting);
5045- 
5046-                         throw  new  Exception (" Not implemented in '"   . get_class(this ) . " ' Relation "   . name);
5047-                     }
50485037
50495038                    /** 
50505039                     * If dynamic update is enabled, saving the record must not take any action 
@@ -5069,7 +5058,18 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
50695058                     * Read the attribute from the referenced model and assign 
50705059                     * it to the current model 
50715060                     */  
5072-                     let  this -> {columns} =  record-> readAttribute(referencedFields);
5061+                     let  columns =  relation-> getFields(),
5062+                       referencedFields =  relation-> getReferencedFields();
5063+                     if  unlikely  typeof  columns ===  " array"   {
5064+                         let  columnCount =  count(columns) -  1 ;
5065+                         for  i in  range(0 , columnCount) {
5066+                             let  columnA =  columns[i];
5067+                             let  columnB =  referencedFields[i];
5068+                             let  this -> {columnA} =  record-> {columnB};
5069+                         }
5070+                     } else  {
5071+                         let  this -> {columns} =  record-> {referencedFields};
5072+                     }
50735073                }
50745074            }
50755075        }
@@ -5105,11 +5105,14 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51055105    protected  function  postSaveRelatedRecords (<AdapterInterface> connection, related, <CollectionInterface> visited ) ->  bool
51065106    {
51075107        var  nesting, className, manager, relation, name, record,
5108-             columns, referencedModel, referencedFields, relatedRecords, value, 
5108+             columns, referencedModel, referencedFields, relatedRecords,
51095109            recordAfter, intermediateModel, intermediateFields,
5110-             intermediateValue,  intermediateModelName,
5111-             intermediateReferencedFields, existingIntermediateModel;
5110+             intermediateModelName,
5111+             intermediateReferencedFields, existingIntermediateModel, columnA, columnB ;
51125112        bool isThrough;
5113+         int  columnCount, referencedFieldsCount, i, j, t, h;
5114+         string  intermediateConditions;
5115+         array  conditions, placeholders;
51135116
51145117        let  nesting =  false ,
51155118            className =  get_class(this ),
@@ -5144,12 +5147,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51445147                    referencedModel =  relation-> getReferencedModel(),
51455148                    referencedFields =  relation-> getReferencedFields();
51465149
5147-                 if  unlikely  typeof  columns ===  " array"   {
5148-                     connection-> rollback(nesting);
5149- 
5150-                     throw  new  Exception (" Not implemented in '"   . className . " ' on Relation "   . name);
5151-                 }
5152- 
51535150                /** 
51545151                 * Create an implicit array for has-many/has-one records 
51555152                 */  
@@ -5159,18 +5156,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51595156                    let  relatedRecords =  record;
51605157                }
51615158
5162-                 if  unlikely  ! fetch  value, this -> {columns} {
5163-                     connection-> rollback(nesting);
5164- 
5165-                     throw  new  Exception (
5166-                         " The column '"   . columns . " ' needs to be present in the model '"   . className . " '" 
5167-                     );
5168-                 }
5169- 
5170-                 /** 
5171-                  * Get the value of the field from the current model 
5172-                  * Check if the relation is a has-many-to-many 
5173-                  */  
51745159                let  isThrough =  (bool) relation-> isThrough();
51755160
51765161                /** 
@@ -5180,7 +5165,38 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51805165                    let  intermediateModelName =  relation-> getIntermediateModel(),
51815166                        intermediateFields =  relation-> getIntermediateFields(),
51825167                        intermediateReferencedFields =  relation-> getIntermediateReferencedFields();
5168+                     let  placeholders =  [];
5169+                     let  conditions =  [];
51835170
5171+                     /** 
5172+                      * Always check for existing intermediate models 
5173+                      * otherwise conflicts will arise on insert instead of update 
5174+                      */  
5175+                     if  unlikely  typeof  columns ===  " array"   {
5176+                         let  columnCount =  count(columns) -  1 ;
5177+                         for  i in  range(0 , columnCount) {
5178+                             let  columnA =  columns[i];
5179+                             let  conditions[] =  " ["  . intermediateFields[i] . " ] = :APR"   . i . " :"  ;
5180+                             let  placeholders[" APR"   . i] =  this -> {columnA};
5181+                         }
5182+                         let  i =  columnCount +  1 ;
5183+                     } else  {
5184+                         let  conditions[] =  " ["   . intermediateFields . " ] = :APR0:"  ;
5185+                         let  placeholders[" APR0"  ] =  this -> {columns};
5186+                         let  i =  1 ;
5187+                     }
5188+                     if  relation-> getType() ===  Relation:: HAS_MANY_THROUGH  {
5189+                         if  unlikely  typeof  referencedFields ===  " array"   {
5190+                             let  referencedFieldsCount =  count(referencedFields) -  1 ;
5191+                             for  j in  range(0 , referencedFieldsCount) {
5192+                                 let  t =  j +  i;
5193+                                 let  conditions[] =  " ["  . intermediateReferencedFields[j] . " ] = :APR"   . t . " :"  ;
5194+                             }
5195+                         } else  {
5196+                             let  conditions[] =  " ["  . intermediateReferencedFields . " ] = :APR"   . i . " :"  ;
5197+                         }
5198+                     }
5199+                     let  intermediateConditions =  join("  AND "  , conditions);
51845200                    for  recordAfter in  relatedRecords {
51855201                        /** 
51865202                         * Save the record and get messages 
@@ -5191,14 +5207,25 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51915207                             * referenced model 
51925208                             */  
51935209                            this -> appendMessagesFrom(recordAfter);
5194-      
5210+ 
51955211                            /** 
51965212                             * Rollback the implicit transaction 
51975213                             */  
51985214                            connection-> rollback(nesting);
5199-      
5215+ 
52005216                            return  false ;
52015217                        }
5218+                         if  relation-> getType() ===  Relation:: HAS_MANY_THROUGH  {
5219+                             if  unlikely  typeof  referencedFields ===  " array"   {
5220+                                 for  j in  range(0 , referencedFieldsCount) {
5221+                                     let  columnA =  referencedFields[j];
5222+                                     let  t =  j +  i;
5223+                                     let  placeholders[" APR"   . t] =  recordAfter-> {columnA};
5224+                                 }
5225+                             } else  {
5226+                                 let  placeholders[" APR"   . i] =  recordAfter-> {referencedFields};
5227+                             }
5228+                         }
52025229                        /** 
52035230                         * Create a new instance of the intermediate model 
52045231                         */  
@@ -5207,45 +5234,43 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
52075234                        );
52085235
52095236                        /** 
5210-                          * Has-one-through relations can only use one intermediate model. 
52115237                         * If it already exist, it can be updated with the new referenced key. 
52125238                         */  
5213-                         if  relation-> getType() ==  Relation:: HAS_ONE_THROUGH  {
5214-                             let  existingIntermediateModel =  intermediateModel-> findFirst(
5215-                                 [
5216-                                     " ["   . intermediateFields . " ] = ?0"  ,
5217-                                     " bind"  : [value]
5218-                                 ]
5219-                             );
5239+                         let  existingIntermediateModel =  intermediateModel-> findFirst(
5240+                             [
5241+                                 intermediateConditions,
5242+                                 " bind"  : placeholders
5243+                             ]
5244+                         );
52205245
5221-                             if  existingIntermediateModel {
5222-                                 let  intermediateModel =  existingIntermediateModel;
5246+                         if  existingIntermediateModel {
5247+                             let  intermediateModel =  existingIntermediateModel;
5248+                         }
5249+                         if  ! existingIntermediateModel ||  relation-> getType() ===  Relation:: HAS_ONE_THROUGH  {
5250+                             /** 
5251+                              * Write value in the intermediate model 
5252+                              */  
5253+                             if  unlikely  typeof  columns ===  " array"   {
5254+                                 for  h in  range(0 , columnCount) {
5255+                                     let  columnA =  columns[h];
5256+                                     let  columnB =  intermediateFields[h];
5257+                                     let  intermediateModel-> {columnB} =  this -> {columnA};
5258+                                 }
5259+                             } else  {
5260+                                 let  intermediateModel-> {intermediateFields} =  this -> {columns};
5261+                             }
5262+                             if  unlikely  typeof  referencedFields ===  " array"   {
5263+                                 let  referencedFieldsCount =  count(referencedFields) -  1 ;
5264+                                 for  h in  range(0 , referencedFieldsCount) {
5265+                                     let  columnA =  referencedFields[h];
5266+                                     let  columnB =  intermediateReferencedFields[h];
5267+                                     let  intermediateModel-> {columnB} =  recordAfter-> {columnA};
5268+                                 }
5269+                             } else  {
5270+                                 let  intermediateModel-> {intermediateReferencedFields} =  recordAfter-> {referencedFields};
52235271                            }
52245272                        }
52255273
5226-                         /** 
5227-                          * Write value in the intermediate model 
5228-                          */  
5229-                         intermediateModel-> writeAttribute(
5230-                             intermediateFields,
5231-                             value
5232-                         );
5233- 
5234-                         /** 
5235-                          * Get the value from the referenced model 
5236-                          */  
5237-                         let  intermediateValue =  recordAfter-> readAttribute(
5238-                             referencedFields
5239-                         );
5240- 
5241-                         /** 
5242-                          * Write the intermediate value in the intermediate model 
5243-                          */  
5244-                         intermediateModel-> writeAttribute(
5245-                             intermediateReferencedFields,
5246-                             intermediateValue
5247-                         );
5248- 
52495274                        /** 
52505275                         * Save the record and get messages 
52515276                         */  
@@ -5264,27 +5289,56 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
52645289                        }
52655290                    }
52665291                } else  {
5267-                     for  recordAfter in  relatedRecords {
5268-                         /** 
5269-                          * Assign the value to the 
5270-                          */  
5271-                         recordAfter-> writeAttribute(referencedFields, value);
5272-                         /** 
5273-                          * Save the record and get messages 
5274-                          */  
5275-                         if  ! recordAfter-> doSave(visited) {
5292+                     if  unlikely  typeof  columns ===  " array"   {
5293+                         let  columnCount =  count(columns) -  1 ;
5294+                         for  recordAfter in  relatedRecords {
5295+                             for  i in  range(0 , columnCount) {
5296+                                 let  columnA =  columns[i];
5297+                                 let  columnB =  referencedFields[i];
5298+                                 let  recordAfter-> {columnB} =  this -> {columnA};
5299+                             }
52765300                            /** 
5277-                              * Get the validation messages generated by the 
5278-                              * referenced model 
5301+                              * Save the record and get messages 
52795302                             */  
5280-                             this -> appendMessagesFrom(recordAfter);
5281-     
5303+                             if  ! recordAfter-> doSave(visited) {
5304+                                 /** 
5305+                                  * Get the validation messages generated by the 
5306+                                  * referenced model 
5307+                                  */  
5308+                                 this -> appendMessagesFrom(recordAfter);
5309+         
5310+                                 /** 
5311+                                  * Rollback the implicit transaction 
5312+                                  */  
5313+                                 connection-> rollback(nesting);
5314+ 
5315+                                 return  false ;
5316+                             }
5317+                         }
5318+                     } else  {
5319+                         for  recordAfter in  relatedRecords {
52825320                            /** 
5283-                              * Rollback  the implicit transaction  
5321+                              * Assign  the value to the  
52845322                             */  
5285-                             connection-> rollback(nesting);
5323+                             let  recordAfter-> {referencedFields} =  this -> {columns};
5324+                             /** 
5325+                              * Save the record and get messages 
5326+                              */  
5327+                             if  ! recordAfter-> doSave(visited) {
52865328
5287-                             return  false ;
5329+                                 /** 
5330+                                  * Get the validation messages generated by the 
5331+                                  * referenced model 
5332+                                  */  
5333+                                 this -> appendMessagesFrom(recordAfter);
5334+         
5335+                                 /** 
5336+                                  * Rollback the implicit transaction 
5337+                                  */  
5338+                                 connection-> rollback(nesting);
5339+ 
5340+                                 return  false ;
5341+                             }
52885342                        }
52895343                    }
52905344                }
0 commit comments