Skip to content

Commit 1f51b7d

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

File tree

3 files changed

+96
-30
lines changed

3 files changed

+96
-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

+69-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-
}
28-
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-
}
4733

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,49 @@ 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+
/** @var TagRepositoryInterface $tagRepository */
75+
$tagRepository = self::$container->get('sulu.repository.tag');
76+
$tag = $tagRepository->createNew();
77+
$tag->setName('Other Tag');
78+
$this->getEntityManager()->persist($tag);
79+
80+
$tags1 = $this->tagFactory->create(['Tag 1']);
81+
$tags2 = $this->tagFactory->create(['Tag 1']);
82+
83+
$this->assertSame($tags1, $tags2);
84+
85+
$this->getEntityManager()->flush();
86+
}
87+
7288
/**
7389
* @return \Generator<mixed[]>
7490
*/
@@ -100,6 +116,7 @@ public function dataProvider(): \Generator
100116
],
101117
[
102118
'Exist Tag 1',
119+
'Other Exist 3',
103120
],
104121
];
105122

@@ -114,4 +131,33 @@ public function dataProvider(): \Generator
114131
],
115132
];
116133
}
134+
135+
/**
136+
* @param string[] $existTagNames
137+
*/
138+
private function createTags(array $existTagNames = []): void
139+
{
140+
/** @var TagRepositoryInterface $tagRepository */
141+
$tagRepository = self::$container->get('sulu.repository.tag');
142+
143+
foreach ($existTagNames as $existTagName) {
144+
$existTag = $tagRepository->createNew();
145+
$existTag->setName($existTagName);
146+
self::getEntityManager()->persist($existTag);
147+
}
148+
149+
if (\count($existTagNames)) {
150+
self::getEntityManager()->flush();
151+
self::getEntityManager()->clear();
152+
}
153+
}
154+
155+
private function createOtherEntity(): object
156+
{
157+
$contact = new Contact();
158+
$contact->setFirstName('Dummy');
159+
$contact->setLastName('Entity');
160+
161+
return $contact;
162+
}
117163
}

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)