From 2b2be2f9096cfa513f04d41145a4b7e110a5b99a Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 11:57:16 -0500 Subject: [PATCH 1/7] Process terms when filling --- src/Processors/FillRelationshipsProcessor.php | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/Processors/FillRelationshipsProcessor.php b/src/Processors/FillRelationshipsProcessor.php index 971ced1..978cb87 100644 --- a/src/Processors/FillRelationshipsProcessor.php +++ b/src/Processors/FillRelationshipsProcessor.php @@ -3,6 +3,7 @@ namespace Stillat\Relationships\Processors; use Statamic\Contracts\Entries\EntryRepository; +use Statamic\Facades\Taxonomy; use Stillat\Relationships\Comparisons\ComparisonResult; use Stillat\Relationships\EntryRelationship; use Stillat\Relationships\Processors\Concerns\GetsFieldValues; @@ -61,19 +62,10 @@ protected function fillRelationships($relationships) } } - protected function fillRelationship(EntryRelationship $relationship) + protected function processData($data, EntryRelationship $relationship) { - $collectionEntries = $this->entries->query() - ->whereIn('collection', [$relationship->leftCollection]) - ->where($relationship->leftField, '!=', null) - ->get(); - - if (count($collectionEntries) == 0) { - return; - } - - foreach ($collectionEntries as $entry) { - $related = $this->getFieldValue($relationship->leftField, $entry, null); + foreach ($data as $item) { + $related = $this->getFieldValue($relationship->leftField, $item, null); if ($related == null) { continue; @@ -86,8 +78,39 @@ protected function fillRelationship(EntryRelationship $relationship) $mockResults = new ComparisonResult(); $mockResults->added = $related; - $this->manager->processor()->setEntryId($entry->id()) + $this->manager->processor()->setEntryId($item->id()) ->processRelationship($relationship, $mockResults); } } + + protected function fillTaxonomyRelationship(EntryRelationship $relationship) + { + $terms = Taxonomy::find($relationship->taxonomyName)->queryTerms()->get(); + + if (count($terms) === 0) { + return; + } + + $this->processData($terms, $relationship); + } + + protected function fillRelationship(EntryRelationship $relationship) + { + if ($relationship->leftCollection === '[term]') { + $this->fillTaxonomyRelationship($relationship); + + return; + } + + $collectionEntries = $this->entries->query() + ->whereIn('collection', [$relationship->leftCollection]) + ->where($relationship->leftField, '!=', null) + ->get(); + + if (count($collectionEntries) == 0) { + return; + } + + $this->processData($collectionEntries, $relationship); + } } From ff9e68e0ea0ca8c041815484aa5dc89a142de3d5 Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 11:58:43 -0500 Subject: [PATCH 2/7] Formatting --- src/RelationshipManager.php | 4 ++-- tests/BaseTestCase.php | 2 +- tests/OneToManyTest.php | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/RelationshipManager.php b/src/RelationshipManager.php index 1902275..973ed91 100644 --- a/src/RelationshipManager.php +++ b/src/RelationshipManager.php @@ -111,9 +111,9 @@ private function getRelationship($left, $right) } return $this->getRelationshipBuilder($left[1], $left[0]) - ->field($left[2], $left[0]) + ->field($left[2], $left[0]) ->isRelatedTo($right[1]) - ->through($right[2], $right[0]); + ->through($right[2], $right[0]); } private function buildOneToOneRelationships($relationships) diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index a8e6014..ecf1f21 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -62,7 +62,7 @@ protected function resolveApplicationConfiguration($app) ]; foreach ($configs as $config) { - $app['config']->set("statamic.$config", require(__DIR__."/__fixtures__/config/{$config}.php")); + $app['config']->set("statamic.$config", require (__DIR__."/__fixtures__/config/{$config}.php")); } $app['config']->set('statamic.antlers.version', 'runtime'); diff --git a/tests/OneToManyTest.php b/tests/OneToManyTest.php index 134b29a..9ff102d 100644 --- a/tests/OneToManyTest.php +++ b/tests/OneToManyTest.php @@ -37,15 +37,15 @@ public function test_explicit_one_to_many() { Relate::clear(); Relate::collection('books') - ->field('author') + ->field('author') ->isRelatedTo('authors') - ->through('books') + ->through('books') ->manyToOne(); Relate::collection('authors') - ->field('books') + ->field('books') ->isRelatedTo('books') - ->through('author') + ->through('author') ->oneToMany(); Entry::find('books-1')->set('author', 'authors-1')->save(); From 6573b5145dd7968a42bc0210f2568a1ff4da8599 Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 11:58:58 -0500 Subject: [PATCH 3/7] Correct issue when processing related data --- src/Processors/RelationshipProcessor.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Processors/RelationshipProcessor.php b/src/Processors/RelationshipProcessor.php index e0d826c..8b6b300 100644 --- a/src/Processors/RelationshipProcessor.php +++ b/src/Processors/RelationshipProcessor.php @@ -25,11 +25,11 @@ class RelationshipProcessor { - use ProcessesManyToMany, - ProcessesOneToOne, + use GetsFieldValues, + ProcessesManyToMany, ProcessesManyToOne, ProcessesOneToMany, - GetsFieldValues; + ProcessesOneToOne; /** * @var EntryRepository @@ -160,6 +160,7 @@ public function getUpdatedEntry() */ protected function updateEntry($entry, $relationship) { + ray('updating', $entry); UpdatingRelatedEntryEvent::dispatch($entry, $this->pristineEntry, $relationship); if (! $this->isDry) { @@ -222,15 +223,24 @@ protected function getEffectedEntries($relationship, $entryIds) /** @var EntryCollection $entries */ $entries = $this->entries->query()->whereIn('id', $entryIds)->get(); - $this->effectedEntries = $entries->keyBy('id')->all(); + $this->effectedEntries = array_merge( + $this->effectedEntries, + $entries->keyBy('id')->all() + ); } elseif ($relationship->rightType == 'user') { $users = $this->getUsersByIds($entryIds); - $this->effectedUsers = $users->keyBy('id')->all(); + $this->effectedUsers = array_merge( + $this->effectedUsers, + $users->keyBy('id')->all() + ); } elseif ($relationship->rightType == 'term') { $terms = $this->getTermsByIds($relationship, $entryIds); - $this->effectedTerms = $terms->keyBy('slug')->all(); + $this->effectedTerms = array_merge( + $this->effectedTerms, + $terms->keyBy('slug')->all() + ); } } From 9c9627a6252e3a134cd952922870019ac07ec3e6 Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 13:44:12 -0500 Subject: [PATCH 4/7] Update save logic --- .phpunit.cache/test-results | 1 + src/Processors/RelationshipProcessor.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .phpunit.cache/test-results diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results new file mode 100644 index 0000000..c36c7a4 --- /dev/null +++ b/.phpunit.cache/test-results @@ -0,0 +1 @@ +{"version":1,"defects":[],"times":{"Tests\\OneToManyTest::test_one_to_many_term_relationships":0.192,"Tests\\ManyToManyDeleteTest::test_many_to_many_delete":0.161,"Tests\\ManyToManyDeleteTest::test_many_to_many_user_delete":0.103,"Tests\\ManyToManyDeleteTest::test_many_to_many_term_delete":0.171,"Tests\\ManyToManyDisabledDeleteTest::test_many_to_many_deletes_can_be_disabled":0.085,"Tests\\ManyToManyDisabledDeleteTest::test_many_to_many_user_deletes_can_be_disabled":0.073,"Tests\\ManyToManyDisabledDeleteTest::test_many_to_many_term_deletes_can_be_disabled":0.109,"Tests\\ManyToManyTest::test_many_to_many_relationship":0.204,"Tests\\ManyToManyTest::test_many_to_many_user_relationships":0.094,"Tests\\ManyToManyTest::test_many_to_many_term_relationships":0.106,"Tests\\ManyToOneDeleteTest::test_many_to_one_delete":0.169,"Tests\\ManyToOneDeleteTest::test_many_to_one_user_delete":0.146,"Tests\\ManyToOneDeleteTest::test_many_to_one_term_delete":0.112,"Tests\\ManyToOneDisabledDeleteTest::test_many_to_one_delete_disabled":0.118,"Tests\\ManyToOneDisabledDeleteTest::test_many_to_one_user_delete_disabled":0.103,"Tests\\ManyToOneDisabledDeleteTest::test_many_to_one_term_delete_disabled":0.07,"Tests\\ManyToOneTest::test_many_to_one_relationship":0.18,"Tests\\ManyToOneTest::test_many_to_one_user_relationship":0.098,"Tests\\ManyToOneTest::test_many_to_one_term_relationship":0.137,"Tests\\OneToManyDeleteTest::test_one_to_many_delete":0.182,"Tests\\OneToManyDeleteTest::test_one_to_many_user_delete":0.115,"Tests\\OneToManyDeleteTest::test_one_to_many_term_delete":0.132,"Tests\\OneToManyDisabledDeleteTest::test_one_to_many_delete_disabled":0.139,"Tests\\OneToManyDisabledDeleteTest::test_one_to_many_user_delete_disabled":0.076,"Tests\\OneToManyDisabledDeleteTest::test_one_to_many_term_delete_disabled":0.08,"Tests\\OneToManyTest::test_one_to_many_relationships":0.197,"Tests\\OneToManyTest::test_explicit_one_to_many":0.2,"Tests\\OneToManyTest::test_one_to_many_user_relationships":0.18,"Tests\\OneToOneDeleteTest::test_one_to_one_delete":0.07,"Tests\\OneToOneDeleteTest::test_one_to_one_user_delete":0.066,"Tests\\OneToOneDeleteTest::test_one_to_one_term_delete":0.071,"Tests\\OneToOneDisabledDeleteTest::test_one_to_one_delete_disabled":0.047,"Tests\\OneToOneDisabledDeleteTest::test_one_to_one_user_disabled_delete":0.041,"Tests\\OneToOneDisabledDeleteTest::test_one_to_one_term_delete_disabled":0.044,"Tests\\OneToOneTest::test_one_to_one_relationship":0.079,"Tests\\OneToOneTest::test_one_to_one_user_relationship":0.069,"Tests\\OneToOneTest::test_one_to_one_term_relationship":0.072,"Tests\\SetNotationRelationshipsTest::test_it_extracts_collection_names":0.01,"Tests\\SetNotationRelationshipsTest::test_it_extracts_collection_names_without_sets":0.011}} \ No newline at end of file diff --git a/src/Processors/RelationshipProcessor.php b/src/Processors/RelationshipProcessor.php index 8b6b300..ba7e1c5 100644 --- a/src/Processors/RelationshipProcessor.php +++ b/src/Processors/RelationshipProcessor.php @@ -165,7 +165,11 @@ protected function updateEntry($entry, $relationship) if (! $this->isDry) { if ($relationship->withEvents) { - $entry->save(); + if ($entry instanceof LocalizedTerm) { + $entry->term()->save(); + } else { + $entry->save(); + } } else { if ($entry instanceof LocalizedTerm) { $entry->term()->saveQuietly(); From b7fcccc5b8ae3a6892371262f0edb0083c1093bf Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 18:23:56 -0500 Subject: [PATCH 5/7] WIP --- src/Listeners/EntrySavedListener.php | 2 +- src/Listeners/EntrySavingListener.php | 2 +- .../Concerns/ProcessesManyToMany.php | 4 ++++ src/Processors/Concerns/ProcessesManyToOne.php | 8 ++++---- src/Processors/Concerns/ProcessesOneToMany.php | 12 ++++++------ src/Processors/RelationshipProcessor.php | 18 ++++++++++++++++-- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Listeners/EntrySavedListener.php b/src/Listeners/EntrySavedListener.php index 914c5f0..2b5d32e 100644 --- a/src/Listeners/EntrySavedListener.php +++ b/src/Listeners/EntrySavedListener.php @@ -31,7 +31,7 @@ public function handle(EntrySaved $event) return; } - if (EventStack::count() > 0) { + if (EventStack::count() > 0 || $this->manager->processor()->isProcessingManyToMany()) { return; } diff --git a/src/Listeners/EntrySavingListener.php b/src/Listeners/EntrySavingListener.php index a1b833f..2aee6af 100644 --- a/src/Listeners/EntrySavingListener.php +++ b/src/Listeners/EntrySavingListener.php @@ -38,7 +38,7 @@ public function handle(EntrySaving $event) return; } - if (EventStack::count() > 1) { + if (EventStack::count() > 1 || $this->manager->processor()->isProcessingManyToMany()) { return; } diff --git a/src/Processors/Concerns/ProcessesManyToMany.php b/src/Processors/Concerns/ProcessesManyToMany.php index d52a72b..5617fde 100644 --- a/src/Processors/Concerns/ProcessesManyToMany.php +++ b/src/Processors/Concerns/ProcessesManyToMany.php @@ -9,6 +9,8 @@ trait ProcessesManyToMany { protected function processManyToMany(ComparisonResult $results, EntryRelationship $relationship) { + $this->processingManyToMany = true; + foreach ($results->added as $addedId) { if (! $this->shouldProcessRelationship($relationship, $addedId)) { continue; @@ -24,5 +26,7 @@ protected function processManyToMany(ComparisonResult $results, EntryRelationshi $this->removeItemFromEntry($relationship, $this->getEffectedEntity($relationship, $removedId)); } + + $this->processingManyToMany = false; } } diff --git a/src/Processors/Concerns/ProcessesManyToOne.php b/src/Processors/Concerns/ProcessesManyToOne.php index ca55f57..93bb09f 100644 --- a/src/Processors/Concerns/ProcessesManyToOne.php +++ b/src/Processors/Concerns/ProcessesManyToOne.php @@ -9,14 +9,14 @@ trait ProcessesManyToOne { protected function processManyToOne(ComparisonResult $results, EntryRelationship $relationship) { - if (! empty($results->added) && count($results->added) == 1 && $this->shouldProcessRelationship($relationship, $results->added[0])) { - $this->addItemToEntry($relationship, $this->getEffectedEntity($relationship, $results->added[0])); - } - foreach ($results->removed as $removedId) { if ($this->shouldProcessRelationship($relationship, $removedId)) { $this->removeItemFromEntry($relationship, $this->getEffectedEntity($relationship, $removedId)); } } + + if (! empty($results->added) && count($results->added) == 1 && $this->shouldProcessRelationship($relationship, $results->added[0])) { + $this->addItemToEntry($relationship, $this->getEffectedEntity($relationship, $results->added[0])); + } } } diff --git a/src/Processors/Concerns/ProcessesOneToMany.php b/src/Processors/Concerns/ProcessesOneToMany.php index 1b0ad37..daf6e07 100644 --- a/src/Processors/Concerns/ProcessesOneToMany.php +++ b/src/Processors/Concerns/ProcessesOneToMany.php @@ -9,16 +9,16 @@ trait ProcessesOneToMany { protected function processOneToMany(ComparisonResult $results, EntryRelationship $relationship) { - foreach ($results->added as $addedId) { - if ($this->shouldProcessRelationship($relationship, $addedId)) { - $this->setFieldValue($relationship, $this->getEffectedEntity($relationship, $addedId)); - } - } - foreach ($results->removed as $removedId) { if ($this->shouldProcessRelationship($relationship, $removedId)) { $this->removeFieldValue($relationship, $this->getEffectedEntity($relationship, $removedId)); } } + + foreach ($results->added as $addedId) { + if ($this->shouldProcessRelationship($relationship, $addedId)) { + $this->setFieldValue($relationship, $this->getEffectedEntity($relationship, $addedId)); + } + } } } diff --git a/src/Processors/RelationshipProcessor.php b/src/Processors/RelationshipProcessor.php index ba7e1c5..f99fa96 100644 --- a/src/Processors/RelationshipProcessor.php +++ b/src/Processors/RelationshipProcessor.php @@ -85,6 +85,15 @@ class RelationshipProcessor protected $isDry = false; + protected $observed = []; + + protected $processingManyToMany = false; + + public function isProcessingManyToMany() + { + return $this->processingManyToMany; + } + public function setIsDeleting($isDeleting = true) { $this->isDelete = $isDeleting; @@ -160,7 +169,6 @@ public function getUpdatedEntry() */ protected function updateEntry($entry, $relationship) { - ray('updating', $entry); UpdatingRelatedEntryEvent::dispatch($entry, $this->pristineEntry, $relationship); if (! $this->isDry) { @@ -460,7 +468,13 @@ protected function removeItemFromEntry($relationship, $entry) $this->updateEntry($entry, $relationship); } else { - $entry->set($relationship->rightField, null); + $value = null; + + if (is_array($rightReference) && count($rightReference) > 0) { + $value = $rightReference; + } + + $entry->set($relationship->rightField, $value); $this->updateEntry($entry, $relationship); } } From a8f63945a122f90b06db4348f52e8499e15ac15d Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 18:24:59 -0500 Subject: [PATCH 6/7] Test coverage for many to many with events --- tests/ManyToManyTest.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/ManyToManyTest.php b/tests/ManyToManyTest.php index 0fb5d29..7f7fefb 100644 --- a/tests/ManyToManyTest.php +++ b/tests/ManyToManyTest.php @@ -37,6 +37,36 @@ public function test_many_to_many_relationship() $this->assertSame([], Entry::find('sponsors-2')->get('sponsoring', [])); } + public function test_many_to_many_relationship_with_events() + { + Relate::clear() + ->manyToMany('conferences.sponsors', 'sponsors.sponsoring') + ->withEvents(); + + Entry::find('sponsors-1')->set('sponsoring', [ + 'conferences-1', + 'conferences-2', + ])->save(); + + Entry::find('sponsors-2')->set('sponsoring', [ + 'conferences-2', + ])->save(); + + $this->assertSame(['sponsors-1', 'sponsors-2'], Entry::find('conferences-2')->get('sponsors')); + $this->assertSame(['sponsors-1'], Entry::find('conferences-1')->get('sponsors')); + + Entry::find('conferences-1')->set('sponsors', ['sponsors-2'])->save(); + + $this->assertSame(['conferences-2'], Entry::find('sponsors-1')->get('sponsoring')); + $this->assertSame(['conferences-2', 'conferences-1'], Entry::find('sponsors-2')->get('sponsoring')); + + Entry::find('conferences-1')->set('sponsors', [])->save(); + Entry::find('conferences-2')->set('sponsors', [])->save(); + + $this->assertSame([], Entry::find('sponsors-1')->get('sponsoring', [])); + $this->assertSame([], Entry::find('sponsors-2')->get('sponsoring', [])); + } + public function test_many_to_many_user_relationships() { Relate::clear() From 1e8b5dbd73fcebbf34885d4e9d7e6431bb026612 Mon Sep 17 00:00:00 2001 From: John Koster Date: Wed, 27 Mar 2024 19:24:49 -0500 Subject: [PATCH 7/7] Refactors --- src/EntryRelationship.php | 21 ++++++++ src/Listeners/EntrySavedListener.php | 2 +- src/Listeners/EntrySavingListener.php | 2 +- .../Concerns/ProcessesManyToMany.php | 4 +- .../Concerns/ProcessesOneToMany.php | 18 +++++++ src/Processors/RelationshipProcessor.php | 30 +++++++++-- src/RelationshipManager.php | 20 ++++++-- tests/OneToManyTest.php | 50 +++++++++++++++++++ tests/RelationshipTestCase.php | 9 ++++ 9 files changed, 145 insertions(+), 11 deletions(-) diff --git a/src/EntryRelationship.php b/src/EntryRelationship.php index 5176da0..af4ccc1 100644 --- a/src/EntryRelationship.php +++ b/src/EntryRelationship.php @@ -14,6 +14,10 @@ class EntryRelationship const TYPE_MANY_TO_ONE = 4; + public ?EntryRelationship $origin = null; + + public ?EntryRelationship $inverted = null; + public $leftType = ''; public $rightType = ''; @@ -115,6 +119,14 @@ public function withEvents($withEvents = true) return $this; } + public function withOriginRelationship(EntryRelationship $relationship) + { + $this->origin = $relationship; + $relationship->inverted = $this; + + return $this; + } + public function isAutomaticInverse($isInverse = true, $inverseIndex = null) { $this->isAutomaticInverse = $isInverse; @@ -128,6 +140,15 @@ public function isAutomaticInverse($isInverse = true, $inverseIndex = null) return $this; } + public function getInverse() + { + if ($this->isAutomaticInverse) { + return $this->origin; + } + + return $this->inverted; + } + /** * Sets whether affected entries will be updated when deleting related entries. * diff --git a/src/Listeners/EntrySavedListener.php b/src/Listeners/EntrySavedListener.php index 2b5d32e..7115f65 100644 --- a/src/Listeners/EntrySavedListener.php +++ b/src/Listeners/EntrySavedListener.php @@ -31,7 +31,7 @@ public function handle(EntrySaved $event) return; } - if (EventStack::count() > 0 || $this->manager->processor()->isProcessingManyToMany()) { + if (EventStack::count() > 0 || $this->manager->processor()->isProcessingRelationships()) { return; } diff --git a/src/Listeners/EntrySavingListener.php b/src/Listeners/EntrySavingListener.php index 2aee6af..59c4166 100644 --- a/src/Listeners/EntrySavingListener.php +++ b/src/Listeners/EntrySavingListener.php @@ -38,7 +38,7 @@ public function handle(EntrySaving $event) return; } - if (EventStack::count() > 1 || $this->manager->processor()->isProcessingManyToMany()) { + if (EventStack::count() > 1 || $this->manager->processor()->isProcessingRelationships()) { return; } diff --git a/src/Processors/Concerns/ProcessesManyToMany.php b/src/Processors/Concerns/ProcessesManyToMany.php index 5617fde..f3931dd 100644 --- a/src/Processors/Concerns/ProcessesManyToMany.php +++ b/src/Processors/Concerns/ProcessesManyToMany.php @@ -9,7 +9,7 @@ trait ProcessesManyToMany { protected function processManyToMany(ComparisonResult $results, EntryRelationship $relationship) { - $this->processingManyToMany = true; + $this->processingRelationships = true; foreach ($results->added as $addedId) { if (! $this->shouldProcessRelationship($relationship, $addedId)) { @@ -27,6 +27,6 @@ protected function processManyToMany(ComparisonResult $results, EntryRelationshi $this->removeItemFromEntry($relationship, $this->getEffectedEntity($relationship, $removedId)); } - $this->processingManyToMany = false; + $this->processingRelationships = false; } } diff --git a/src/Processors/Concerns/ProcessesOneToMany.php b/src/Processors/Concerns/ProcessesOneToMany.php index daf6e07..babf56b 100644 --- a/src/Processors/Concerns/ProcessesOneToMany.php +++ b/src/Processors/Concerns/ProcessesOneToMany.php @@ -2,6 +2,7 @@ namespace Stillat\Relationships\Processors\Concerns; +use Statamic\Facades\Data; use Stillat\Relationships\Comparisons\ComparisonResult; use Stillat\Relationships\EntryRelationship; @@ -11,12 +12,29 @@ protected function processOneToMany(ComparisonResult $results, EntryRelationship { foreach ($results->removed as $removedId) { if ($this->shouldProcessRelationship($relationship, $removedId)) { + $this->dependencies[] = $removedId; + $this->dependencies[] = $this->getDependency($relationship, $removedId); $this->removeFieldValue($relationship, $this->getEffectedEntity($relationship, $removedId)); } } foreach ($results->added as $addedId) { if ($this->shouldProcessRelationship($relationship, $addedId)) { + $this->dependencies[] = $addedId; + $dependent = Data::find($this->getDependency($relationship, $addedId)); + + if ($dependent !== null && $inverse = $relationship->getInverse()) { + $leftReference = $dependent->get($relationship->leftField); + + if (($key = array_search($addedId, $leftReference)) !== false) { + unset($leftReference[$key]); + + $dependent->set($relationship->leftField, array_values($leftReference)); + + $dependent->saveQuietly(); + } + } + $this->setFieldValue($relationship, $this->getEffectedEntity($relationship, $addedId)); } } diff --git a/src/Processors/RelationshipProcessor.php b/src/Processors/RelationshipProcessor.php index f99fa96..ef11b4b 100644 --- a/src/Processors/RelationshipProcessor.php +++ b/src/Processors/RelationshipProcessor.php @@ -87,11 +87,13 @@ class RelationshipProcessor protected $observed = []; - protected $processingManyToMany = false; + protected $processingRelationships = false; - public function isProcessingManyToMany() + protected $dependencies = []; + + public function isProcessingRelationships() { - return $this->processingManyToMany; + return $this->processingRelationships; } public function setIsDeleting($isDeleting = true) @@ -307,9 +309,11 @@ public function process($relationships) public function processRelationship($relationship, $results) { + $this->processingRelationships = true; UpdatingRelationshipsEvent::dispatch($relationship, $results); if (! $results->hasChanges()) { + $this->processingRelationships = false; UpdatedRelationshipsEvent::dispatch($relationship, $results); return; @@ -326,6 +330,7 @@ public function processRelationship($relationship, $results) } elseif ($relationship->type == EntryRelationship::TYPE_MANY_TO_ONE) { $this->processManyToOne($results, $relationship); } + $this->processingRelationships = false; UpdatedRelationshipsEvent::dispatch($relationship, $results); } @@ -354,6 +359,25 @@ protected function shouldProcessRelationship(EntryRelationship $relationship, $i return true; } + protected function getDependency(EntryRelationship $relationship, $id) + { + $data = null; + + if ($relationship->rightType == 'entry') { + $data = $this->effectedEntries[$id]; + } elseif ($relationship->rightType == 'user') { + $data = $this->effectedUsers[$id]; + } elseif ($relationship->rightType == 'term') { + $data = $this->effectedTerms[$id]; + } + + if ($data === null || ! method_exists($data, 'get')) { + return null; + } + + return $data->get($relationship->rightField); + } + protected function getEffectedEntity(EntryRelationship $relationship, $id) { if ($relationship->rightType == 'entry') { diff --git a/src/RelationshipManager.php b/src/RelationshipManager.php index 973ed91..11c669e 100644 --- a/src/RelationshipManager.php +++ b/src/RelationshipManager.php @@ -125,7 +125,10 @@ private function buildOneToOneRelationships($relationships) $right = $this->getFieldDetails($relationship[1]); $builtRelationships[] = $this->getRelationship($left, $right)->oneToOne(); - $builtRelationships[] = $this->getRelationship($right, $left)->oneToOne()->isAutomaticInverse(); + $builtRelationships[] = $this->getRelationship($right, $left) + ->oneToOne() + ->isAutomaticInverse() + ->withOriginRelationship($builtRelationships[0]); } return new RelationshipProxy($builtRelationships); @@ -150,7 +153,10 @@ private function buildOneToManyRelationships($relationships) $right = $this->getFieldDetails($relationship[1]); $builtRelationships[] = $this->getRelationship($left, $right)->manyToOne(); - $builtRelationships[] = $this->getRelationship($right, $left)->oneToMany()->isAutomaticInverse(); + $builtRelationships[] = $this->getRelationship($right, $left) + ->oneToMany() + ->isAutomaticInverse() + ->withOriginRelationship($builtRelationships[0]); } return new RelationshipProxy($builtRelationships); @@ -175,7 +181,10 @@ private function buildManyToOneRelationships($relationships) $right = $this->getFieldDetails($relationship[1]); $builtRelationships[] = $this->getRelationship($left, $right)->oneToOne(); - $builtRelationships[] = $this->getRelationship($right, $left)->manyToOne()->isAutomaticInverse(); + $builtRelationships[] = $this->getRelationship($right, $left) + ->manyToOne() + ->isAutomaticInverse() + ->withOriginRelationship($builtRelationships[0]); } return new RelationshipProxy($builtRelationships); @@ -254,7 +263,10 @@ private function buildManyToManyRelationships($relationships) $right = $this->getFieldDetails($relationship[1]); $builtRelationships[] = $this->getRelationship($left, $right)->manyToMany(); - $builtRelationships[] = $this->getRelationship($right, $left)->manyToMany()->isAutomaticInverse(); + $builtRelationships[] = $this->getRelationship($right, $left) + ->manyToMany() + ->isAutomaticInverse() + ->withOriginRelationship($builtRelationships[0]); } return new RelationshipProxy($builtRelationships); diff --git a/tests/OneToManyTest.php b/tests/OneToManyTest.php index 9ff102d..e30afa8 100644 --- a/tests/OneToManyTest.php +++ b/tests/OneToManyTest.php @@ -117,4 +117,54 @@ public function test_one_to_many_term_relationships() $this->assertSame([], $this->getTerm('topics-one')->get('posts', [])); $this->assertSame([], $this->getTerm('topics-two')->get('posts', [])); } + + public function test_one_to_many_updates_dependents() + { + Relate::clear(); + Relate::oneToMany( + 'books.author', + 'authors.books' + ); + + Entry::find('books-1')->set('author', 'authors-1')->save(); + Entry::find('books-2')->set('author', 'authors-1')->save(); + Entry::find('books-3')->set('author', 'authors-1')->save(); + + Entry::find('books-4')->set('author', 'authors-1')->save(); + Entry::find('books-5')->set('author', 'authors-2')->save(); + + Entry::find('authors-1')->set('books', [ + 'books-1', + 'books-2', + 'books-3', + ])->save(); + + Entry::find('authors-2')->set('books', [ + 'books-4', + 'books-5', + ])->save(); + + Entry::find('authors-1')->set('books', [ + 'books-1', + 'books-2', + 'books-3', + 'books-4', + ])->save(); + + $this->assertSame(['books-5'], Entry::find('authors-2')->get('books')); + + $this->assertSame([ + 'books-1', + 'books-2', + 'books-3', + 'books-4', + ], Entry::find('authors-1')->get('books')); + + $this->assertSame('authors-1', Entry::find('books-1')->get('author')); + $this->assertSame('authors-1', Entry::find('books-2')->get('author')); + $this->assertSame('authors-1', Entry::find('books-3')->get('author')); + $this->assertSame('authors-1', Entry::find('books-4')->get('author')); + + $this->assertSame('authors-2', Entry::find('books-5')->get('author')); + } } diff --git a/tests/RelationshipTestCase.php b/tests/RelationshipTestCase.php index 1f5ed14..b0381d9 100644 --- a/tests/RelationshipTestCase.php +++ b/tests/RelationshipTestCase.php @@ -157,6 +157,15 @@ protected function createCollectionEntries() [ 'title' => 'Book Two', ], + [ + 'title' => 'Book Three', + ], + [ + 'title' => 'Book Four', + ], + [ + 'title' => 'Book Five', + ], ]); $this->createEntries('conferences', [