diff --git a/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php b/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php index 2eb3ff88..ae3c75b9 100644 --- a/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php +++ b/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php @@ -153,6 +153,54 @@ trait EntityMergerHelperTrait ); } + /** + * Perform an OR operation on the boolean values from the target and the other entity for the given field. + * This effectively means that the value is true, if it is true in at least one of the entities. + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function useTrueValue(object $target, object $other, string $field): object + { + return $this->useCallback( + function (bool $target_value, bool $other_value): bool { + return $target_value || $other_value; + }, + $target, + $other, + $field + ); + } + + /** + * Perform a merge of comma separated lists from the target and the other entity for the given field. + * The values are merged and duplicates are removed. + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function mergeTags(object $target, object $other, string $field, string $separator = ','): object + { + return $this->useCallback( + function (string $t, string $o) use ($separator): string { + //Explode the strings into arrays + $t_array = explode($separator, $t); + $o_array = explode($separator, $o); + + //Merge the arrays and remove duplicates + $tmp = array_unique(array_merge($t_array, $o_array)); + + //Implode the array back to a string + return implode($separator, $tmp); + }, + $target, + $other, + $field + ); + } + /** * Merge the collections from the target and the other entity for the given field and put all items into the target collection. * @param object $target diff --git a/src/Services/EntityMergers/Mergers/PartMerger.php b/src/Services/EntityMergers/Mergers/PartMerger.php index c25d0dc6..a3962118 100644 --- a/src/Services/EntityMergers/Mergers/PartMerger.php +++ b/src/Services/EntityMergers/Mergers/PartMerger.php @@ -55,7 +55,12 @@ class PartMerger implements EntityMergerInterface //We assume that the higher value is the correct one for minimum instock $this->useLargerValue($target, $other, 'minamount'); + //We assume that a part needs review and is a favorite if one of the parts is + $this->useTrueValue($target, $other, 'needs_review'); + $this->useTrueValue($target, $other, 'favorite'); + //Merge the tags using the tag merger + $this->mergeTags($target, $other, 'tags'); return $target; } diff --git a/tests/Services/EntityMergers/Mergers/PartMergerTest.php b/tests/Services/EntityMergers/Mergers/PartMergerTest.php index c9b7956c..591172b3 100644 --- a/tests/Services/EntityMergers/Mergers/PartMergerTest.php +++ b/tests/Services/EntityMergers/Mergers/PartMergerTest.php @@ -20,6 +20,10 @@ namespace App\Tests\Services\EntityMergers\Mergers; +use App\Entity\Parts\Category; +use App\Entity\Parts\Footprint; +use App\Entity\Parts\Manufacturer; +use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; use App\Services\EntityMergers\Mergers\PartMerger; @@ -38,11 +42,65 @@ class PartMergerTest extends KernelTestCase $this->merger = self::getContainer()->get(PartMerger::class); } + public function testMergeOfEntityRelations(): void + { + $category = new Category(); + $footprint = new Footprint(); + $manufacturer1 = new Manufacturer(); + $manufacturer2 = new Manufacturer(); + $unit = new MeasurementUnit(); + + $part1 = (new Part()) + ->setCategory($category) + ->setManufacturer($manufacturer1); + + $part2 = (new Part()) + ->setFootprint($footprint) + ->setManufacturer($manufacturer2) + ->setPartUnit($unit); + + $merged = $this->merger->merge($part1, $part2); + $this->assertSame($merged, $part1); + $this->assertSame($category, $merged->getCategory()); + $this->assertSame($footprint, $merged->getFootprint()); + $this->assertSame($manufacturer1, $merged->getManufacturer()); + $this->assertSame($unit, $merged->getPartUnit()); + } + + public function testMergeOfTags(): void + { + $part1 = (new Part()) + ->setTags('tag1,tag2,tag3'); + + $part2 = (new Part()) + ->setTags('tag2,tag3,tag4'); + + $merged = $this->merger->merge($part1, $part2); + $this->assertSame($merged, $part1); + $this->assertSame('tag1,tag2,tag3,tag4', $merged->getTags()); + } + + public function testMergeOfBoolFields(): void + { + $part1 = (new Part()) + ->setFavorite(false) + ->setNeedsReview(true); + + $part2 = (new Part()) + ->setFavorite(true) + ->setNeedsReview(false); + + $merged = $this->merger->merge($part1, $part2); + //Favorite and needs review should be true, as it is true in one of the parts + $this->assertTrue($merged->isFavorite()); + $this->assertTrue($merged->isNeedsReview()); + } + /** * This test also functions as test for EntityMergerHelperTrait::mergeCollections() so its pretty long. * @return void */ - public function testMergePartLots() + public function testMergeOfPartLots(): void { $lot1 = (new PartLot())->setAmount(2)->setNeedsRefill(true); $lot2 = (new PartLot())->setInstockUnknown(true)->setVendorBarcode('test');