@@ -44,7 +44,7 @@ abstract class Join
44
44
protected $ kind ;
45
45
46
46
/** Weak join does not update foreign table. */
47
- protected bool $ weak = false ;
47
+ public bool $ weak = false ;
48
48
49
49
/**
50
50
* Normally the foreign table is saved first, then it's ID is used in the
@@ -59,7 +59,7 @@ abstract class Join
59
59
* of saving and delete needs to be reversed. In this case $reverse
60
60
* will be set to `true`. You can specify value of this property.
61
61
*/
62
- protected bool $ reverse = false ;
62
+ public bool $ reverse = false ;
63
63
64
64
/**
65
65
* Field to be used for matching inside master table.
@@ -85,9 +85,6 @@ abstract class Join
85
85
*/
86
86
protected string $ prefix = '' ;
87
87
88
- /** @var mixed ID indexed by spl_object_id(entity) used by a joined table. */
89
- protected $ idByOid ;
90
-
91
88
/** @var array<int, array<string, mixed>> Data indexed by spl_object_id(entity) which is populated here as the save/insert progresses. */
92
89
private array $ saveBufferByOid = [];
93
90
@@ -234,7 +231,7 @@ protected function init(): void
234
231
->addMoreInfo ('model ' , $ this ->getOwner ());
235
232
}
236
233
237
- if ($ this ->reverse === true ) {
234
+ if ($ this ->reverse ) {
238
235
if ($ this ->masterField && $ this ->masterField !== $ idField ) { // TODO not implemented yet, see https://github.com/atk4/data/issues/803
239
236
throw (new Exception ('Joining tables on non-id fields is not implemented yet ' ))
240
237
->addMoreInfo ('masterField ' , $ this ->masterField )
@@ -271,16 +268,25 @@ protected function init(): void
271
268
protected function initJoinHooks (): void
272
269
{
273
270
$ this ->onHookToOwnerEntity (Model::HOOK_AFTER_LOAD , \Closure::fromCallable ([$ this , 'afterLoad ' ]));
274
- $ this ->onHookToOwnerEntity (Model::HOOK_AFTER_UNLOAD , \Closure::fromCallable ([$ this , 'afterUnload ' ]));
271
+
272
+ $ createHookFxWithCleanup = function (string $ methodName ): \Closure {
273
+ return function (Model $ entity , &...$ args ) use ($ methodName ): void {
274
+ try {
275
+ $ this ->{$ methodName }($ entity , ...$ args );
276
+ } finally {
277
+ $ this ->unsetSaveBuffer ($ entity );
278
+ }
279
+ };
280
+ };
275
281
276
282
if ($ this ->reverse ) {
277
- $ this ->onHookToOwnerEntity (Model::HOOK_AFTER_INSERT , \Closure:: fromCallable ([ $ this , 'afterInsert ' ] ), [], -5 );
278
- $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_UPDATE , \Closure:: fromCallable ([ $ this , 'beforeUpdate ' ] ), [], -5 );
279
- $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_DELETE , \Closure:: fromCallable ([ $ this , ' doDelete ' ] ), [], -5 );
283
+ $ this ->onHookToOwnerEntity (Model::HOOK_AFTER_INSERT , $ createHookFxWithCleanup ( 'afterInsert ' ), [], -5 );
284
+ $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_UPDATE , $ createHookFxWithCleanup ( 'beforeUpdate ' ), [], -5 );
285
+ $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_DELETE , $ createHookFxWithCleanup ( ' beforeDelete ' ), [], -5 );
280
286
} else {
281
- $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_INSERT , \Closure:: fromCallable ([ $ this , 'beforeInsert ' ] ), [], -5 );
282
- $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_UPDATE , \Closure:: fromCallable ([ $ this , 'beforeUpdate ' ] ), [], -5 );
283
- $ this ->onHookToOwnerEntity (Model::HOOK_AFTER_DELETE , \Closure:: fromCallable ([ $ this , ' doDelete ' ] ));
287
+ $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_INSERT , $ createHookFxWithCleanup ( 'beforeInsert ' ), [], -5 );
288
+ $ this ->onHookToOwnerEntity (Model::HOOK_BEFORE_UPDATE , $ createHookFxWithCleanup ( 'beforeUpdate ' ), [], -5 );
289
+ $ this ->onHookToOwnerEntity (Model::HOOK_AFTER_DELETE , $ createHookFxWithCleanup ( ' beforeDelete ' ));
284
290
}
285
291
}
286
292
@@ -418,36 +424,6 @@ protected function assertReferenceIdNotNull($value): void
418
424
}
419
425
}
420
426
421
- /**
422
- * @return mixed
423
- *
424
- * @internal should be not used outside atk4/data
425
- */
426
- protected function getId (Model $ entity )
427
- {
428
- return $ this ->idByOid [spl_object_id ($ entity )];
429
- }
430
-
431
- /**
432
- * @param mixed $id
433
- *
434
- * @internal should be not used outside atk4/data
435
- */
436
- protected function setId (Model $ entity , $ id ): void
437
- {
438
- $ this ->assertReferenceIdNotNull ($ id );
439
-
440
- $ this ->idByOid [spl_object_id ($ entity )] = $ id ;
441
- }
442
-
443
- /**
444
- * @internal should be not used outside atk4/data
445
- */
446
- protected function unsetId (Model $ entity ): void
447
- {
448
- unset($ this ->idByOid [spl_object_id ($ entity )]);
449
- }
450
-
451
427
/**
452
428
* @internal should be not used outside atk4/data
453
429
*/
@@ -461,7 +437,7 @@ protected function issetSaveBuffer(Model $entity): bool
461
437
*
462
438
* @internal should be not used outside atk4/data
463
439
*/
464
- protected function getReindexedDataAndUnsetSaveBuffer (Model $ entity ): array
440
+ protected function getAndUnsetReindexedSaveBuffer (Model $ entity ): array
465
441
{
466
442
$ resOur = $ this ->saveBufferByOid [spl_object_id ($ entity )];
467
443
$ this ->unsetSaveBuffer ($ entity );
@@ -474,18 +450,10 @@ protected function getReindexedDataAndUnsetSaveBuffer(Model $entity): array
474
450
return $ res ;
475
451
}
476
452
477
- /**
478
- * @internal should be not used outside atk4/data
479
- */
480
- protected function unsetSaveBuffer (Model $ entity ): void
481
- {
482
- unset($ this ->saveBufferByOid [spl_object_id ($ entity )]);
483
- }
484
-
485
453
/**
486
454
* @param mixed $value
487
455
*/
488
- public function setSaveBufferValue (Model $ entity , string $ fieldName , $ value ): void
456
+ protected function setSaveBufferValue (Model $ entity , string $ fieldName , $ value ): void
489
457
{
490
458
$ entity ->assertIsEntity ($ this ->getOwner ());
491
459
@@ -496,26 +464,44 @@ public function setSaveBufferValue(Model $entity, string $fieldName, $value): vo
496
464
$ this ->saveBufferByOid [spl_object_id ($ entity )][$ fieldName ] = $ value ;
497
465
}
498
466
499
- public function afterLoad (Model $ entity ): void
467
+ /**
468
+ * @internal should be not used outside atk4/data
469
+ */
470
+ protected function unsetSaveBuffer (Model $ entity ): void
500
471
{
472
+ unset($ this ->saveBufferByOid [spl_object_id ($ entity )]);
501
473
}
502
474
503
- protected function afterUnload (Model $ entity ): void
475
+ protected function afterLoad (Model $ entity ): void
504
476
{
505
- $ this ->unsetId ($ entity );
506
- $ this ->unsetSaveBuffer ($ entity );
477
+ }
478
+
479
+ protected function initSaveBuffer (Model $ entity , bool $ fromUpdate ): void
480
+ {
481
+ foreach ($ entity ->get () as $ name => $ value ) {
482
+ $ field = $ entity ->getField ($ name );
483
+ if (!$ field ->hasJoin () || $ field ->getJoin ()->shortName !== $ this ->shortName || $ field ->readOnly || $ field ->neverPersist || $ field ->neverSave ) {
484
+ continue ;
485
+ }
486
+
487
+ if ($ fromUpdate && !$ entity ->isDirty ($ name )) {
488
+ continue ;
489
+ }
490
+
491
+ $ field ->getJoin ()->setSaveBufferValue ($ entity , $ name , $ value );
492
+ }
507
493
}
508
494
509
495
/**
510
496
* @param array<string, mixed> $data
511
497
*/
512
- public function beforeInsert (Model $ entity , array &$ data ): void
498
+ protected function beforeInsert (Model $ entity , array &$ data ): void
513
499
{
514
500
if ($ this ->weak ) {
515
501
return ;
516
502
}
517
503
518
- $ model = $ this ->getOwner ( );
504
+ $ this ->initSaveBuffer ( $ entity , false );
519
505
520
506
// the value for the masterField is set, so we are going to use existing record anyway
521
507
if ($ entity ->get ($ this ->masterField ) !== null ) {
@@ -524,69 +510,67 @@ public function beforeInsert(Model $entity, array &$data): void
524
510
525
511
$ foreignModel = $ this ->getForeignModel ();
526
512
$ foreignEntity = $ foreignModel ->createEntity ()
527
- ->setMulti ($ this ->getReindexedDataAndUnsetSaveBuffer ($ entity ))
528
- /* ->set ($this->foreignField, null) */ ;
513
+ ->setMulti ($ this ->getAndUnsetReindexedSaveBuffer ($ entity ))
514
+ -> setNull ($ this ->foreignField ) ;
529
515
$ foreignEntity ->save ();
530
516
531
- $ this ->setId ($ entity , $ foreignEntity ->getId ());
517
+ $ foreignId = $ foreignEntity ->getId ();
518
+ $ this ->assertReferenceIdNotNull ($ foreignId );
532
519
533
520
if ($ this ->hasJoin ()) {
534
- $ this ->getJoin ()->setSaveBufferValue ($ entity , $ this ->masterField , $ this -> getId ( $ entity ) );
521
+ $ this ->getJoin ()->setSaveBufferValue ($ entity , $ this ->masterField , $ foreignId );
535
522
} else {
536
- $ data [$ this ->masterField ] = $ this -> getId ( $ entity ) ;
523
+ $ data [$ this ->masterField ] = $ foreignId ;
537
524
}
538
-
539
- // $entity->set($this->masterField, $this->getId($entity)); // TODO needed? from array persistence
540
525
}
541
526
542
- public function afterInsert (Model $ entity ): void
527
+ protected function afterInsert (Model $ entity ): void
543
528
{
544
529
if ($ this ->weak ) {
545
530
return ;
546
531
}
547
532
548
- $ id = $ this ->hasJoin () ? $ this ->getJoin ()->getId ($ entity ) : $ entity ->getId ();
533
+ $ this ->initSaveBuffer ($ entity , false );
534
+
535
+ $ id = $ entity ->getId ();
549
536
$ this ->assertReferenceIdNotNull ($ id );
550
- // $this->setSaveBufferValue($entity, $this->masterField, $id); // TODO needed? from array persistence
551
537
552
538
$ foreignModel = $ this ->getForeignModel ();
553
539
$ foreignEntity = $ foreignModel ->createEntity ()
554
- ->setMulti ($ this ->getReindexedDataAndUnsetSaveBuffer ($ entity ))
540
+ ->setMulti ($ this ->getAndUnsetReindexedSaveBuffer ($ entity ))
555
541
->set ($ this ->foreignField , $ id );
556
542
$ foreignEntity ->save ();
557
-
558
- $ this ->setId ($ entity , $ entity ->getId ()); // TODO why is this here? it seems to be not needed
559
543
}
560
544
561
545
/**
562
546
* @param array<string, mixed> $data
563
547
*/
564
- public function beforeUpdate (Model $ entity , array &$ data ): void
548
+ protected function beforeUpdate (Model $ entity , array &$ data ): void
565
549
{
566
550
if ($ this ->weak ) {
567
551
return ;
568
552
}
569
553
554
+ $ this ->initSaveBuffer ($ entity , true );
555
+
570
556
if (!$ this ->issetSaveBuffer ($ entity )) {
571
557
return ;
572
558
}
573
559
574
560
$ foreignModel = $ this ->getForeignModel ();
575
561
$ foreignId = $ this ->reverse ? $ entity ->getId () : $ entity ->get ($ this ->masterField );
576
562
$ this ->assertReferenceIdNotNull ($ foreignId );
577
- $ saveBuffer = $ this ->getReindexedDataAndUnsetSaveBuffer ($ entity );
563
+ $ saveBuffer = $ this ->getAndUnsetReindexedSaveBuffer ($ entity );
578
564
$ foreignModel ->atomic (function () use ($ foreignModel , $ foreignId , $ saveBuffer ) {
579
565
$ foreignModel = (clone $ foreignModel )->addCondition ($ this ->foreignField , $ foreignId );
580
566
foreach ($ foreignModel as $ foreignEntity ) {
581
567
$ foreignEntity ->setMulti ($ saveBuffer );
582
568
$ foreignEntity ->save ();
583
569
}
584
570
});
585
-
586
- // $this->setId($entity, ??); // TODO needed? from array persistence
587
571
}
588
572
589
- public function doDelete (Model $ entity ): void
573
+ protected function beforeDelete (Model $ entity ): void
590
574
{
591
575
if ($ this ->weak ) {
592
576
return ;
@@ -601,7 +585,5 @@ public function doDelete(Model $entity): void
601
585
$ foreignEntity ->delete ();
602
586
}
603
587
});
604
-
605
- $ this ->unsetId ($ entity ); // TODO needed? from array persistence
606
588
}
607
589
}
0 commit comments