@@ -4996,8 +4996,8 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
4996
4996
4997
4997
protected function preSaveRelatedRecords (<AdapterInterface> connection, related, <CollectionInterface> visited ) -> bool
4998
4998
{
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;
5001
5001
let nesting = false ;
5002
5002
5003
5003
/**
@@ -5034,17 +5034,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5034
5034
" Only objects can be stored as part of belongs-to relations in '" . get_class(this ) . " ' Relation " . name
5035
5035
);
5036
5036
}
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
- }
5048
5037
5049
5038
/**
5050
5039
* If dynamic update is enabled, saving the record must not take any action
@@ -5069,7 +5058,18 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5069
5058
* Read the attribute from the referenced model and assign
5070
5059
* it to the current model
5071
5060
*/
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
+ }
5073
5073
}
5074
5074
}
5075
5075
}
@@ -5105,11 +5105,14 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5105
5105
protected function postSaveRelatedRecords (<AdapterInterface> connection, related, <CollectionInterface> visited ) -> bool
5106
5106
{
5107
5107
var nesting, className, manager, relation, name, record,
5108
- columns, referencedModel, referencedFields, relatedRecords, value,
5108
+ columns, referencedModel, referencedFields, relatedRecords,
5109
5109
recordAfter, intermediateModel, intermediateFields,
5110
- intermediateValue, intermediateModelName,
5111
- intermediateReferencedFields, existingIntermediateModel;
5110
+ intermediateModelName,
5111
+ intermediateReferencedFields, existingIntermediateModel, columnA, columnB ;
5112
5112
bool isThrough;
5113
+ int columnCount, referencedFieldsCount, i, j, t;
5114
+ string intermediateConditions;
5115
+ array conditions, placeholders;
5113
5116
5114
5117
let nesting = false ,
5115
5118
className = get_class(this ),
@@ -5144,12 +5147,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5144
5147
referencedModel = relation-> getReferencedModel(),
5145
5148
referencedFields = relation-> getReferencedFields();
5146
5149
5147
- if unlikely typeof columns === " array" {
5148
- connection-> rollback(nesting);
5149
-
5150
- throw new Exception (" Not implemented in '" . className . " ' on Relation " . name);
5151
- }
5152
-
5153
5150
/**
5154
5151
* Create an implicit array for has-many/has-one records
5155
5152
*/
@@ -5159,18 +5156,6 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5159
5156
let relatedRecords = record;
5160
5157
}
5161
5158
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
- */
5174
5159
let isThrough = (bool) relation-> isThrough();
5175
5160
5176
5161
/**
@@ -5180,7 +5165,36 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5180
5165
let intermediateModelName = relation-> getIntermediateModel(),
5181
5166
intermediateFields = relation-> getIntermediateFields(),
5182
5167
intermediateReferencedFields = relation-> getIntermediateReferencedFields();
5168
+ let placeholders = [];
5169
+ let conditions = [];
5183
5170
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);
5184
5198
for recordAfter in relatedRecords {
5185
5199
/**
5186
5200
* Save the record and get messages
@@ -5191,14 +5205,23 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5191
5205
* referenced model
5192
5206
*/
5193
5207
this -> appendMessagesFrom(recordAfter);
5194
-
5208
+
5195
5209
/**
5196
5210
* Rollback the implicit transaction
5197
5211
*/
5198
5212
connection-> rollback(nesting);
5199
-
5213
+
5200
5214
return false ;
5201
5215
}
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
+ }
5202
5225
/**
5203
5226
* Create a new instance of the intermediate model
5204
5227
*/
@@ -5207,44 +5230,42 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5207
5230
);
5208
5231
5209
5232
/**
5210
- * Has-one-through relations can only use one intermediate model.
5211
5233
* If it already exist, it can be updated with the new referenced key.
5212
5234
*/
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
+ );
5220
5241
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};
5223
5250
}
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};
5224
5268
}
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
- );
5248
5269
5249
5270
/**
5250
5271
* Save the record and get messages
@@ -5264,27 +5285,56 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface,
5264
5285
}
5265
5286
}
5266
5287
} 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
+ }
5276
5296
/**
5277
- * Get the validation messages generated by the
5278
- * referenced model
5297
+ * Save the record and get messages
5279
5298
*/
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 {
5282
5316
/**
5283
- * Rollback the implicit transaction
5317
+ * Assign the value to the
5284
5318
*/
5285
- connection-> rollback(nesting);
5319
+ let recordAfter-> {referencedFields} = this -> {columns};
5320
+ /**
5321
+ * Save the record and get messages
5322
+ */
5323
+ if ! recordAfter-> doSave(visited) {
5286
5324
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
+ }
5288
5338
}
5289
5339
}
5290
5340
}
0 commit comments