@@ -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;
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,36 @@ 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+ 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 unlikely typeof referencedFields === " array" {
5189+ let referencedFieldsCount = count(referencedFields) - 1 ;
5190+ for j in range(0 , referencedFieldsCount) {
5191+ let t = j + i;
5192+ let conditions[] = " [" . intermediateReferencedFields[j] . " ] = :APR" . t . " :" ;
5193+ }
5194+ } else {
5195+ let conditions[] = " [" . intermediateReferencedFields . " ] = :APR" . i . " :" ;
5196+ }
5197+ let intermediateConditions = join(" AND " , conditions);
51845198 for recordAfter in relatedRecords {
51855199 /**
51865200 * Save the record and get messages
@@ -5191,14 +5205,23 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
51915205 * referenced model
51925206 */
51935207 this -> appendMessagesFrom(recordAfter);
5194-
5208+
51955209 /**
51965210 * Rollback the implicit transaction
51975211 */
51985212 connection-> rollback(nesting);
5199-
5213+
52005214 return false ;
52015215 }
5216+ if unlikely typeof referencedFields === " array" {
5217+ for j in range(0 , referencedFieldsCount) {
5218+ let columnA = referencedFields[j];
5219+ let t = j + i;
5220+ let placeholders[" APR" . t] = recordAfter-> {columnA};
5221+ }
5222+ } else {
5223+ let placeholders[" APR" . i] = recordAfter-> {referencedFields};
5224+ }
52025225 /**
52035226 * Create a new instance of the intermediate model
52045227 */
@@ -5207,44 +5230,42 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
52075230 );
52085231
52095232 /**
5210- * Has-one-through relations can only use one intermediate model.
52115233 * If it already exist, it can be updated with the new referenced key.
52125234 */
5213- if relation-> getType() == Relation:: HAS_ONE_THROUGH {
5214- let existingIntermediateModel = intermediateModel-> findFirst(
5215- [
5216- " [" . intermediateFields . " ] = ?0" ,
5217- " bind" : [value]
5218- ]
5219- );
5235+ let existingIntermediateModel = intermediateModel-> findFirst(
5236+ [
5237+ intermediateConditions,
5238+ " bind" : placeholders
5239+ ]
5240+ );
52205241
5221- if existingIntermediateModel {
5222- let intermediateModel = existingIntermediateModel;
5242+ if existingIntermediateModel {
5243+ let intermediateModel = existingIntermediateModel;
5244+ }
5245+ if unlikely typeof columns === " array" {
5246+ for i in range(0 , columnCount) {
5247+ let columnA = columns[i];
5248+ let columnB = intermediateFields[i];
5249+ let intermediateModel-> {columnB} = this -> {columnA};
52235250 }
5251+ } else {
5252+ /**
5253+ * Write value in the intermediate model
5254+ */
5255+ let intermediateModel-> {intermediateFields} = this -> {columns};
5256+ }
5257+ if unlikely typeof referencedFields === " array" {
5258+ for i in range(0 , referencedFieldsCount) {
5259+ let columnA = referencedFields[i];
5260+ let columnB = intermediateReferencedFields[i];
5261+ let intermediateModel-> {columnB} = recordAfter-> {columnA};
5262+ }
5263+ } else {
5264+ /**
5265+ * Write the intermediate value in the intermediate model
5266+ */
5267+ let intermediateModel-> {intermediateReferencedFields} = recordAfter-> {referencedFields};
52245268 }
5225-
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- );
52485269
52495270 /**
52505271 * Save the record and get messages
@@ -5264,27 +5285,56 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
52645285 }
52655286 }
52665287 } 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) {
5288+ if unlikely typeof columns === " array" {
5289+ let columnCount = count(columns) - 1 ;
5290+ for recordAfter in relatedRecords {
5291+ for i in range(0 , columnCount) {
5292+ let columnA = columns[i];
5293+ let columnB = referencedFields[i];
5294+ let recordAfter-> {columnB} = this -> {columnA};
5295+ }
52765296 /**
5277- * Get the validation messages generated by the
5278- * referenced model
5297+ * Save the record and get messages
52795298 */
5280- this -> appendMessagesFrom(recordAfter);
5281-
5299+ if ! recordAfter-> doSave(visited) {
5300+ /**
5301+ * Get the validation messages generated by the
5302+ * referenced model
5303+ */
5304+ this -> appendMessagesFrom(recordAfter);
5305+
5306+ /**
5307+ * Rollback the implicit transaction
5308+ */
5309+ connection-> rollback(nesting);
5310+
5311+ return false ;
5312+ }
5313+ }
5314+ } else {
5315+ for recordAfter in relatedRecords {
52825316 /**
5283- * Rollback the implicit transaction
5317+ * Assign the value to the
52845318 */
5285- connection-> rollback(nesting);
5319+ let recordAfter-> {referencedFields} = this -> {columns};
5320+ /**
5321+ * Save the record and get messages
5322+ */
5323+ if ! recordAfter-> doSave(visited) {
52865324
5287- return false ;
5325+ /**
5326+ * Get the validation messages generated by the
5327+ * referenced model
5328+ */
5329+ this -> appendMessagesFrom(recordAfter);
5330+
5331+ /**
5332+ * Rollback the implicit transaction
5333+ */
5334+ connection-> rollback(nesting);
5335+
5336+ return false ;
5337+ }
52885338 }
52895339 }
52905340 }
0 commit comments