Skip to content

Commit e9adeca

Browse files
Fix bug create tag with same name multiple times
1 parent 29afa52 commit e9adeca

File tree

3 files changed

+89
-30
lines changed

3 files changed

+89
-30
lines changed

Content/Infrastructure/Doctrine/TagFactory.php

+25-6
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,41 @@ public function create(array $tagNames): array
5252
// sort tags by the given names order
5353
$excerptTags = [];
5454
foreach ($tags as $tag) {
55-
$excerptTags[array_search($tag->getName(), $tagNames, true)] = $tag;
55+
$index = array_search($tag->getName(), $tagNames, true);
56+
$excerptTags[$index] = $tag;
57+
unset($tagNames[$index]);
5658
}
5759

58-
// create tags which not exist yet
59-
foreach ($tagNames as $key => $tagName) {
60-
if (isset($excerptTags[$key])) {
61-
continue;
60+
// check if a tag with the same name was yet persisted and use that instead of create one
61+
// this avoids a unique constraint error to create multiple tag with same name
62+
if (\count($tagNames)) {
63+
// we use here the unitOfWork instead of an own cache this avoid us listing for
64+
// flush, clear or deletion events and so we don't need to invalid an cache ourselves
65+
foreach ($this->entityManager->getUnitOfWork()->getScheduledEntityInsertions() as $object) {
66+
if (!$object instanceof TagInterface) {
67+
continue;
68+
}
69+
70+
$index = array_search($object->getName(), $tagNames, true);
71+
72+
if (false === $index) {
73+
continue;
74+
}
75+
76+
$excerptTags[$index] = $object;
77+
unset($tagNames[$index]);
6278
}
79+
}
6380

81+
// create missing tags which not exist yet
82+
foreach ($tagNames as $index => $tagName) {
6483
/** @var TagInterface $tag */
6584
$tag = $this->tagRepository->createNew();
6685
$tag->setName($tagName);
6786

6887
$this->entityManager->persist($tag);
6988

70-
$excerptTags[$key] = $tag;
89+
$excerptTags[$index] = $tag;
7190
}
7291

7392
return $excerptTags;

Tests/Functional/Content/Infrastructure/Doctrine/TagFactoryTest.php

+62-23
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,25 @@
1313

1414
namespace Sulu\Bundle\ContentBundle\Tests\Functional\Content\Infrastructure\Doctrine;
1515

16+
use Sulu\Bundle\ContactBundle\Entity\Contact;
1617
use Sulu\Bundle\ContentBundle\Content\Domain\Factory\TagFactoryInterface;
1718
use Sulu\Bundle\TagBundle\Tag\TagInterface;
1819
use Sulu\Bundle\TagBundle\Tag\TagRepositoryInterface;
1920
use Sulu\Bundle\TestBundle\Testing\SuluTestCase;
2021

2122
class TagFactoryTest extends SuluTestCase
2223
{
24+
/**
25+
* @var TagFactoryInterface
26+
*/
27+
private $tagFactory;
28+
2329
protected function setUp(): void
2430
{
2531
self::bootKernel();
2632
self::purgeDatabase();
27-
}
2833

29-
/**
30-
* @param string[] $existTagNames
31-
*/
32-
protected function createTagFactory(array $existTagNames = []): TagFactoryInterface
33-
{
34-
/** @var TagRepositoryInterface $tagRepository */
35-
$tagRepository = self::$container->get('sulu.repository.tag');
36-
37-
foreach ($existTagNames as $existTagName) {
38-
$existTag = $tagRepository->createNew();
39-
$existTag->setName($existTagName);
40-
self::getEntityManager()->persist($existTag);
41-
}
42-
43-
if (\count($existTagNames)) {
44-
self::getEntityManager()->flush();
45-
self::getEntityManager()->clear();
46-
}
47-
48-
return self::$container->get('sulu_content.tag_factory');
34+
$this->tagFactory = self::$container->get('sulu_content.tag_factory');
4935
}
5036

5137
/**
@@ -56,19 +42,43 @@ protected function createTagFactory(array $existTagNames = []): TagFactoryInterf
5642
*/
5743
public function testCreate(array $tagNames, array $existTags): void
5844
{
59-
$tagFactory = $this->createTagFactory($existTags);
45+
$this->createTags($existTags);
46+
47+
$tags = $this->tagFactory->create($tagNames);
6048

6149
$this->assertSame(
6250
$tagNames,
6351
array_map(
6452
function (TagInterface $tag) {
6553
return $tag->getName();
6654
},
67-
$tagFactory->create($tagNames)
55+
$tags
6856
)
6957
);
7058
}
7159

60+
public function testCreateSameTagTwice(): void
61+
{
62+
$tags1 = $this->tagFactory->create(['Tag 1']);
63+
$tags2 = $this->tagFactory->create(['Tag 1']);
64+
65+
$this->assertSame($tags1, $tags2);
66+
67+
$this->getEntityManager()->flush();
68+
}
69+
70+
public function testCreateSameTagTwiceWithOtherEntityInUnitOfWork(): void
71+
{
72+
$this->getEntityManager()->persist($this->createOtherEntity());
73+
74+
$tags1 = $this->tagFactory->create(['Tag 1']);
75+
$tags2 = $this->tagFactory->create(['Tag 1']);
76+
77+
$this->assertSame($tags1, $tags2);
78+
79+
$this->getEntityManager()->flush();
80+
}
81+
7282
/**
7383
* @return \Generator<mixed[]>
7484
*/
@@ -114,4 +124,33 @@ public function dataProvider(): \Generator
114124
],
115125
];
116126
}
127+
128+
/**
129+
* @param string[] $existTagNames
130+
*/
131+
private function createTags(array $existTagNames = []): void
132+
{
133+
/** @var TagRepositoryInterface $tagRepository */
134+
$tagRepository = self::$container->get('sulu.repository.tag');
135+
136+
foreach ($existTagNames as $existTagName) {
137+
$existTag = $tagRepository->createNew();
138+
$existTag->setName($existTagName);
139+
self::getEntityManager()->persist($existTag);
140+
}
141+
142+
if (\count($existTagNames)) {
143+
self::getEntityManager()->flush();
144+
self::getEntityManager()->clear();
145+
}
146+
}
147+
148+
private function createOtherEntity(): object
149+
{
150+
$contact = new Contact();
151+
$contact->setFirstName('Dummy');
152+
$contact->setLastName('Entity');
153+
154+
return $contact;
155+
}
117156
}

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@
7878
"Tests/Application/bin/adminconsole sulu:build dev --env dev"
7979
],
8080
"bootstrap-test-environment": [
81-
"Tests/Application/bin/adminconsole doctrine:database:create --if-not-exists --env test",
81+
"Tests/Application/bin/adminconsole doctrine:database:drop --if-exists --force --env test",
82+
"Tests/Application/bin/adminconsole doctrine:database:create --env test",
8283
"Tests/Application/bin/adminconsole doctrine:schema:update --force --env test"
8384
],
8485
"lint": [

0 commit comments

Comments
 (0)