Skip to content

Commit 52dea77

Browse files
TatevikGrtatevikg1
andauthored
Add a dryRun option to subscriber csv import (#347)
Co-authored-by: Tatevik <[email protected]>
1 parent 9ba5c10 commit 52dea77

File tree

6 files changed

+62
-30
lines changed

6 files changed

+62
-30
lines changed

src/Domain/Subscription/Model/Dto/SubscriberImportOptions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class SubscriberImportOptions
1212
public function __construct(
1313
public readonly bool $updateExisting = false,
1414
public readonly array $listIds = [],
15+
public readonly bool $dryRun = false,
1516
) {
1617
}
1718
}

src/Domain/Subscription/Service/Manager/SubscriberAttributeManager.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpList\Core\Domain\Subscription\Service\Manager;
66

7+
use Doctrine\ORM\EntityManagerInterface;
78
use PhpList\Core\Domain\Subscription\Exception\SubscriberAttributeCreationException;
89
use PhpList\Core\Domain\Subscription\Model\Subscriber;
910
use PhpList\Core\Domain\Subscription\Model\SubscriberAttributeDefinition;
@@ -13,10 +14,14 @@
1314
class SubscriberAttributeManager
1415
{
1516
private SubscriberAttributeValueRepository $attributeRepository;
17+
private EntityManagerInterface $entityManager;
1618

17-
public function __construct(SubscriberAttributeValueRepository $attributeRepository)
18-
{
19+
public function __construct(
20+
SubscriberAttributeValueRepository $attributeRepository,
21+
EntityManagerInterface $entityManager,
22+
) {
1923
$this->attributeRepository = $attributeRepository;
24+
$this->entityManager = $entityManager;
2025
}
2126

2227
public function createOrUpdate(
@@ -37,7 +42,7 @@ public function createOrUpdate(
3742
}
3843

3944
$subscriberAttribute->setValue($value);
40-
$this->attributeRepository->save($subscriberAttribute);
45+
$this->entityManager->persist($subscriberAttribute);
4146

4247
return $subscriberAttribute;
4348
}

src/Domain/Subscription/Service/Manager/SubscriberManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public function createFromImport(ImportSubscriberDto $subscriberDto): Subscriber
120120
$subscriber->setDisabled($subscriberDto->disabled);
121121
$subscriber->setExtraData($subscriberDto->extraData);
122122

123-
$this->subscriberRepository->save($subscriber);
123+
$this->entityManager->persist($subscriber);
124124

125125
return $subscriber;
126126
}

src/Domain/Subscription/Service/SubscriberCsvImporter.php

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpList\Core\Domain\Subscription\Service;
66

7+
use Doctrine\ORM\EntityManagerInterface;
78
use PhpList\Core\Domain\Subscription\Model\Dto\ImportSubscriberDto;
89
use PhpList\Core\Domain\Subscription\Model\Dto\SubscriberImportOptions;
910
use PhpList\Core\Domain\Subscription\Model\Subscriber;
@@ -18,6 +19,7 @@
1819

1920
/**
2021
* Service for importing subscribers from a CSV file.
22+
* @SuppressWarnings("CouplingBetweenObjects")
2123
*/
2224
class SubscriberCsvImporter
2325
{
@@ -27,21 +29,24 @@ class SubscriberCsvImporter
2729
private SubscriberRepository $subscriberRepository;
2830
private CsvImporter $csvImporter;
2931
private SubscriberAttributeDefinitionRepository $attrDefinitionRepository;
32+
private EntityManagerInterface $entityManager;
3033

3134
public function __construct(
3235
SubscriberManager $subscriberManager,
3336
SubscriberAttributeManager $attributeManager,
3437
SubscriptionManager $subscriptionManager,
3538
SubscriberRepository $subscriberRepository,
3639
CsvImporter $csvImporter,
37-
SubscriberAttributeDefinitionRepository $attrDefinitionRepository
40+
SubscriberAttributeDefinitionRepository $attrDefinitionRepository,
41+
EntityManagerInterface $entityManager
3842
) {
3943
$this->subscriberManager = $subscriberManager;
4044
$this->attributeManager = $attributeManager;
4145
$this->subscriptionManager = $subscriptionManager;
4246
$this->subscriberRepository = $subscriberRepository;
4347
$this->csvImporter = $csvImporter;
4448
$this->attrDefinitionRepository = $attrDefinitionRepository;
49+
$this->entityManager = $entityManager;
4550
}
4651

4752
/**
@@ -72,6 +77,9 @@ public function importFromCsv(UploadedFile $file, SubscriberImportOptions $optio
7277
foreach ($result['valid'] as $dto) {
7378
try {
7479
$this->processRow($dto, $options, $stats);
80+
if (!$options->dryRun) {
81+
$this->entityManager->flush();
82+
}
7583
} catch (Throwable $e) {
7684
$stats['errors'][] = 'Error processing ' . $dto->email . ': ' . $e->getMessage();
7785
$stats['skipped']++;
@@ -91,24 +99,30 @@ public function importFromCsv(UploadedFile $file, SubscriberImportOptions $optio
9199

92100
/**
93101
* Import subscribers with an update strategy.
94-
*
102+
* @SuppressWarnings("BooleanArgumentFlag")
95103
* @param UploadedFile $file The uploaded CSV file
96104
* @return array Import statistics
97105
*/
98-
public function importAndUpdateFromCsv(UploadedFile $file, ?array $listIds = []): array
106+
public function importAndUpdateFromCsv(UploadedFile $file, ?array $listIds = [], bool $dryRun = false): array
99107
{
100-
return $this->importFromCsv($file, new SubscriberImportOptions(updateExisting: true, listIds: $listIds));
108+
return $this->importFromCsv(
109+
file: $file,
110+
options: new SubscriberImportOptions(updateExisting: true, listIds: $listIds, dryRun: $dryRun)
111+
);
101112
}
102113

103114
/**
104115
* Import subscribers without updating existing ones.
105-
*
116+
* @SuppressWarnings("BooleanArgumentFlag")
106117
* @param UploadedFile $file The uploaded CSV file
107118
* @return array Import statistics
108119
*/
109-
public function importNewFromCsv(UploadedFile $file, ?array $listIds = []): array
120+
public function importNewFromCsv(UploadedFile $file, ?array $listIds = [], bool $dryRun = false): array
110121
{
111-
return $this->importFromCsv($file, new SubscriberImportOptions(listIds: $listIds));
122+
return $this->importFromCsv(
123+
file: $file,
124+
options: new SubscriberImportOptions(listIds: $listIds, dryRun: $dryRun)
125+
);
112126
}
113127

114128
/**
@@ -158,9 +172,9 @@ private function processAttributes(Subscriber $subscriber, ImportSubscriberDto $
158172
$attributeDefinition = $this->attrDefinitionRepository->findOneByName($key);
159173
if ($attributeDefinition !== null) {
160174
$this->attributeManager->createOrUpdate(
161-
$subscriber,
162-
$attributeDefinition,
163-
$value
175+
subscriber: $subscriber,
176+
definition: $attributeDefinition,
177+
value: $value
164178
);
165179
}
166180
}

tests/Unit/Domain/Subscription/Service/SubscriberAttributeManagerTest.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpList\Core\Tests\Unit\Domain\Subscription\Service;
66

7+
use Doctrine\ORM\EntityManagerInterface;
78
use PhpList\Core\Domain\Subscription\Exception\SubscriberAttributeCreationException;
89
use PhpList\Core\Domain\Subscription\Model\Subscriber;
910
use PhpList\Core\Domain\Subscription\Model\SubscriberAttributeDefinition;
@@ -20,19 +21,20 @@ public function testCreateNewSubscriberAttribute(): void
2021
$definition = new SubscriberAttributeDefinition();
2122

2223
$subscriberAttrRepo = $this->createMock(SubscriberAttributeValueRepository::class);
24+
$entityManager = $this->createMock(EntityManagerInterface::class);
2325

2426
$subscriberAttrRepo->expects(self::once())
2527
->method('findOneBySubscriberAndAttribute')
2628
->with($subscriber, $definition)
2729
->willReturn(null);
2830

29-
$subscriberAttrRepo->expects(self::once())
30-
->method('save')
31+
$entityManager->expects(self::once())
32+
->method('persist')
3133
->with(self::callback(function (SubscriberAttributeValue $attr) {
3234
return $attr->getValue() === 'US';
3335
}));
3436

35-
$manager = new SubscriberAttributeManager($subscriberAttrRepo);
37+
$manager = new SubscriberAttributeManager($subscriberAttrRepo, $entityManager);
3638
$attribute = $manager->createOrUpdate($subscriber, $definition, 'US');
3739

3840
self::assertInstanceOf(SubscriberAttributeValue::class, $attribute);
@@ -47,16 +49,18 @@ public function testUpdateExistingSubscriberAttribute(): void
4749
$existing->setValue('Old');
4850

4951
$subscriberAttrRepo = $this->createMock(SubscriberAttributeValueRepository::class);
52+
$entityManager = $this->createMock(EntityManagerInterface::class);
53+
5054
$subscriberAttrRepo->expects(self::once())
5155
->method('findOneBySubscriberAndAttribute')
5256
->with($subscriber, $definition)
5357
->willReturn($existing);
5458

55-
$subscriberAttrRepo->expects(self::once())
56-
->method('save')
59+
$entityManager->expects(self::once())
60+
->method('persist')
5761
->with($existing);
5862

59-
$manager = new SubscriberAttributeManager($subscriberAttrRepo);
63+
$manager = new SubscriberAttributeManager($subscriberAttrRepo, $entityManager);
6064
$result = $manager->createOrUpdate($subscriber, $definition, 'Updated');
6165

6266
self::assertSame('Updated', $result->getValue());
@@ -68,9 +72,11 @@ public function testCreateFailsWhenValueAndDefaultAreNull(): void
6872
$definition = new SubscriberAttributeDefinition();
6973

7074
$subscriberAttrRepo = $this->createMock(SubscriberAttributeValueRepository::class);
75+
$entityManager = $this->createMock(EntityManagerInterface::class);
76+
7177
$subscriberAttrRepo->method('findOneBySubscriberAndAttribute')->willReturn(null);
7278

73-
$manager = new SubscriberAttributeManager($subscriberAttrRepo);
79+
$manager = new SubscriberAttributeManager($subscriberAttrRepo, $entityManager);
7480

7581
$this->expectException(SubscriberAttributeCreationException::class);
7682
$this->expectExceptionMessage('Value is required');
@@ -81,14 +87,15 @@ public function testCreateFailsWhenValueAndDefaultAreNull(): void
8187
public function testGetSubscriberAttribute(): void
8288
{
8389
$subscriberAttrRepo = $this->createMock(SubscriberAttributeValueRepository::class);
84-
$expected = new SubscriberAttributeValue(new SubscriberAttributeDefinition(), new Subscriber());
90+
$entityManager = $this->createMock(EntityManagerInterface::class);
8591

92+
$expected = new SubscriberAttributeValue(new SubscriberAttributeDefinition(), new Subscriber());
8693
$subscriberAttrRepo->expects(self::once())
8794
->method('findOneBySubscriberIdAndAttributeId')
8895
->with(5, 10)
8996
->willReturn($expected);
9097

91-
$manager = new SubscriberAttributeManager($subscriberAttrRepo);
98+
$manager = new SubscriberAttributeManager($subscriberAttrRepo, $entityManager);
9299
$result = $manager->getSubscriberAttribute(5, 10);
93100

94101
self::assertSame($expected, $result);
@@ -98,12 +105,13 @@ public function testDeleteSubscriberAttribute(): void
98105
{
99106
$subscriberAttrRepo = $this->createMock(SubscriberAttributeValueRepository::class);
100107
$attribute = $this->createMock(SubscriberAttributeValue::class);
108+
$entityManager = $this->createMock(EntityManagerInterface::class);
101109

102110
$subscriberAttrRepo->expects(self::once())
103111
->method('remove')
104112
->with($attribute);
105113

106-
$manager = new SubscriberAttributeManager($subscriberAttrRepo);
114+
$manager = new SubscriberAttributeManager($subscriberAttrRepo, $entityManager);
107115
$manager->delete($attribute);
108116

109117
self::assertTrue(true);

tests/Unit/Domain/Subscription/Service/SubscriberCsvImportManagerTest.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpList\Core\Tests\Unit\Domain\Subscription\Service;
66

7+
use Doctrine\ORM\EntityManagerInterface;
78
use PhpList\Core\Domain\Subscription\Model\Dto\ImportSubscriberDto;
89
use PhpList\Core\Domain\Subscription\Model\Dto\SubscriberImportOptions;
910
use PhpList\Core\Domain\Subscription\Model\Subscriber;
@@ -27,6 +28,7 @@ class SubscriberCsvImportManagerTest extends TestCase
2728
private SubscriberRepository&MockObject $subscriberRepositoryMock;
2829
private CsvImporter&MockObject $csvImporterMock;
2930
private SubscriberAttributeDefinitionRepository&MockObject $attributeDefinitionRepositoryMock;
31+
private EntityManagerInterface $entityManager;
3032
private SubscriberCsvImporter $subject;
3133

3234
protected function setUp(): void
@@ -37,14 +39,16 @@ protected function setUp(): void
3739
$this->subscriberRepositoryMock = $this->createMock(SubscriberRepository::class);
3840
$this->csvImporterMock = $this->createMock(CsvImporter::class);
3941
$this->attributeDefinitionRepositoryMock = $this->createMock(SubscriberAttributeDefinitionRepository::class);
42+
$this->entityManager = $this->createMock(EntityManagerInterface::class);
4043

4144
$this->subject = new SubscriberCsvImporter(
42-
$this->subscriberManagerMock,
43-
$this->attributeManagerMock,
44-
$this->subscriptionManagerMock,
45-
$this->subscriberRepositoryMock,
46-
$this->csvImporterMock,
47-
$this->attributeDefinitionRepositoryMock
45+
subscriberManager: $this->subscriberManagerMock,
46+
attributeManager: $this->attributeManagerMock,
47+
subscriptionManager: $this->subscriptionManagerMock,
48+
subscriberRepository: $this->subscriberRepositoryMock,
49+
csvImporter: $this->csvImporterMock,
50+
attrDefinitionRepository: $this->attributeDefinitionRepositoryMock,
51+
entityManager: $this->entityManager,
4852
);
4953
}
5054

0 commit comments

Comments
 (0)