@@ -58,6 +58,11 @@ class ManyField extends CompositeField
58
58
*/
59
59
protected $ fieldCallbacks = [];
60
60
61
+ /**
62
+ *
63
+ */
64
+ protected $ manyChildren = [];
65
+
61
66
/**
62
67
* @param string $name
63
68
* @param array $children
@@ -67,12 +72,12 @@ public function __construct($name, $children = null) {
67
72
Requirements::css ('fullscreeninteractive/silverstripe-manyfield:client/css/ManyField.css ' );
68
73
69
74
if ($ children instanceof FieldList) {
70
- $ this ->children = $ children ;
75
+ $ this ->manyChildren = $ children ;
71
76
} else if (is_array ($ children )) {
72
- $ this ->children = new FieldList ($ children );
77
+ $ this ->manyChildren = new FieldList ($ children );
73
78
}
74
-
75
- $ this ->children -> setContainerField ( $ this );
79
+
80
+ $ this ->children = new FieldList ( );
76
81
$ this ->brokenOnConstruct = false ;
77
82
78
83
FormField::__construct ($ name , null );
@@ -233,7 +238,7 @@ public function saveInto(DataObjectInterface $record)
233
238
} else if ($ record ->hasField ($ this ->name )) {
234
239
$ record ->setCastedField ($ this ->name , json_encode ($ this ->dataValue ()));
235
240
} else if ($ record ->getRelationType ($ this ->name )) {
236
- // @todo
241
+ $ this -> updateRelation ( $ record , true );
237
242
}
238
243
}
239
244
@@ -287,7 +292,7 @@ public function generateRow($index, $value = null)
287
292
$ row = CompositeField::create ();
288
293
$ row ->addExtraClass ("row manyfield__row " );
289
294
290
- foreach ($ this ->children as $ child ) {
295
+ foreach ($ this ->manyChildren as $ child ) {
291
296
$ field = clone $ child ;
292
297
$ field ->name = $ this ->name . '[ ' .$ child ->name . '][ ' . $ index . '] ' ;
293
298
@@ -307,4 +312,77 @@ public function AbsoluteLink($action = null)
307
312
{
308
313
return Director::absoluteURL ($ this ->Link ($ action ));
309
314
}
315
+
316
+ /**
317
+ * Helper for going through all the values in this manymany field and
318
+ * delete or create new records. This method won't be perfect for every case
319
+ * but it'll handle most cases as long as the Field name matches the
320
+ * relation name.
321
+ */
322
+ public function updateRelation (DataObjectInterface $ record , $ delete = true )
323
+ {
324
+ $ existing = $ record ->{$ this ->name }();
325
+ $ removed = [];
326
+
327
+ // if no value then we should clear everything out
328
+ if (!$ this ->value ) {
329
+ if ($ delete ) {
330
+ foreach ($ existing as $ row ) {
331
+ $ row ->delete ();
332
+ }
333
+ } else {
334
+ $ existing ->removeAll ();
335
+ }
336
+
337
+ return $ this ;
338
+ }
339
+
340
+ foreach ($ existing as $ row ) {
341
+ if (!isset ($ this ->value ['ID ' ])) {
342
+ throw new Exception ('Missing ID field in ManyMany field list. ' );
343
+ }
344
+
345
+ if (!isset ($ this ->value ['ID ' ][$ row ->ID ])) {
346
+ // missing so delete or remove.
347
+ if ($ delete ) {
348
+ $ existing ->find ('ID ' , $ row ->ID )->delete ();
349
+ } else {
350
+ $ existing ->removeById ($ row ->ID );
351
+ }
352
+ }
353
+
354
+ foreach ($ this ->value ['ID ' ] as $ key => $ id ) {
355
+ if ($ id ) {
356
+ $ idKeyMap [$ key ] = $ id ;
357
+ }
358
+ }
359
+
360
+ foreach ($ this ->value as $ col => $ values ) {
361
+ if ($ col == 'ID ' ) {
362
+ continue ;
363
+ }
364
+
365
+ foreach ($ values as $ key => $ value ) {
366
+ if (!isset ($ updatedData [$ key ])) {
367
+ $ updatedData [$ key ] = [];
368
+ }
369
+
370
+ $ updatedData [$ key ][$ col ] = $ value ;
371
+ }
372
+ }
373
+
374
+ foreach ($ updatedData as $ key => $ data ) {
375
+ if (isset ($ idKeyMap [$ key ])) {
376
+ $ existing ->find ('ID ' , $ idKeyMap [$ key ])->update ($ row );
377
+ } else {
378
+ $ create = Injector::inst ()->create ($ existing ->dataClass ());
379
+ $ create ->update ($ data );
380
+ $ create ->write ();
381
+ $ existing ->add ($ create );
382
+ }
383
+ }
384
+ }
385
+
386
+ return $ this ;
387
+ }
310
388
}
0 commit comments