@@ -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