Prevent duplicate terms being created

Within the `PostFactory` class, ensure that when using the `withTags`
method and creating tag terms that an existing term doesn't already
exist for a given name before trying to create it.

With the previous implementation, there would be multiple terms if the
PostFactory was used multiple times with the same tag name.

Given that `PostFactory` now has a dependency on `EntityTypeManger`,
this has been added as a service within `opdavies_blog_test` and needs
to be resolved from the container before trying to use it within a test.

This commit also updates the usages in `PostTest` so that those tests
continue to work and pass.

References 
This commit is contained in:
Oliver Davies 2020-10-07 13:02:43 +01:00
parent b90ca42e87
commit 059e237600
4 changed files with 41 additions and 10 deletions
web/modules/custom/blog/tests

View file

@ -1,3 +1,6 @@
services:
Drupal\opdavies_blog\Service\PostPusher\PostPusher:
alias: Drupal\opdavies_blog\Service\PostPusher\NullPostPusher
Drupal\opdavies_blog_test\Factory\PostFactory:
autowire: true

View file

@ -5,6 +5,9 @@ declare(strict_types=1);
namespace Drupal\opdavies_blog_test\Factory;
use Assert\Assert;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\Entity\Node;
use Drupal\opdavies_blog\Entity\Node\Post;
use Drupal\taxonomy\Entity\Term;
@ -13,11 +16,17 @@ use Tightenco\Collect\Support\Collection;
final class PostFactory {
private EntityStorageInterface $termStorage;
private Collection $tags;
private string $title = 'This is a test blog post';
public function __construct() {
public function __construct(
EntityTypeManagerInterface $entityTypeManager
) {
$this->termStorage = $entityTypeManager->getStorage('taxonomy_term');
$this->tags = new Collection();
}
@ -47,15 +56,25 @@ final class PostFactory {
}
public function withTags(array $tags): self {
$this->tags = new Collection();
foreach ($tags as $tag) {
Assert::that($tag)->notEmpty()->string();
$this->tags->push(
Term::create(['vid' => 'tags', 'name' => $tag])
);
$this->tags->push($this->createOrReferenceTag($tag));
}
return $this;
}
private function createOrReferenceTag(string $tag): EntityInterface {
$existingTags = $this->termStorage->loadByProperties(['name' => $tag]);
if ($existingTags) {
return reset($existingTags);
}
return Term::create(['vid' => 'tags', 'name' => $tag]);
}
}

View file

@ -24,14 +24,16 @@ final class PostTest extends EntityKernelTestBase {
'opdavies_blog_test',
];
private PostFactory $postFactory;
/** @test */
public function it_can_determine_if_a_post_contains_a_tweet(): void {
$post = (new PostFactory())->create();
$post = $this->postFactory->create();
$post->save();
$this->assertFalse($post->hasTweet());
$post = (new PostFactory())->create([Post::FIELD_HAS_TWEET => TRUE]);
$post = $this->postFactory->create([Post::FIELD_HAS_TWEET => TRUE]);
$post->save();
$this->assertTrue($post->hasTweet());
@ -39,7 +41,7 @@ final class PostTest extends EntityKernelTestBase {
/** @test */
public function it_converts_a_post_to_a_tweet(): void {
$post = (new PostFactory())
$post = $this->postFactory
->setTitle('Creating a custom PHPUnit command for DDEV')
->withTags(['Automated testing', 'DDEV', 'Drupal', 'Drupal 8', 'PHP'])
->create();
@ -59,7 +61,7 @@ final class PostTest extends EntityKernelTestBase {
/** @test */
public function certain_terms_are_not_added_as_hashtags(): void {
$post = (new PostFactory())
$post = $this->postFactory
->setTitle('Drupal Planet should not be added as a hashtag')
->withTags(['Drupal', 'Drupal Planet', 'PHP'])
->create();
@ -80,6 +82,8 @@ final class PostTest extends EntityKernelTestBase {
protected function setUp() {
parent::setUp();
$this->postFactory = $this->container->get(PostFactory::class);
$this->installEntitySchema('taxonomy_term');
$this->installConfig(['opdavies_blog_test']);

View file

@ -9,16 +9,20 @@ use Drupal\opdavies_blog_test\Factory\PostFactory;
final class RelatedPostsTest extends PostTestBase {
private PostFactory $postFactory;
private RelatedPostsRepository $relatedPostsRepository;
/** @test */
public function it_returns_related_posts(): void {
$postA = (new PostFactory())->setTitle('Post A')
$postA = $this->postFactory
->setTitle('Post A')
->withTags(['Drupal 8'])
->create();
$postA->save();
$postB = (new PostFactory())->setTitle('Post B')
$postB = $this->postFactory
->setTitle('Post B')
->withTags(['Drupal 8'])
->create();
$postB->save();
@ -32,6 +36,7 @@ final class RelatedPostsTest extends PostTestBase {
protected function setUp() {
parent::setUp();
$this->postFactory = $this->container->get(PostFactory::class);
$this->relatedPostsRepository = $this->container->get(RelatedPostsRepository::class);
}