Skip to content

Commit 68ffccc

Browse files
committed
EventLogManager
1 parent dc99df1 commit 68ffccc

File tree

6 files changed

+236
-9
lines changed

6 files changed

+236
-9
lines changed

config/services/managers.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ services:
44
autoconfigure: true
55
public: false
66

7+
PhpList\Core\Domain\Configuration\Service\Manager\ConfigManager:
8+
autowire: true
9+
autoconfigure: true
10+
11+
PhpList\Core\Domain\Configuration\Service\Manager\EventLogManager:
12+
autowire: true
13+
autoconfigure: true
14+
715
PhpList\Core\Domain\Identity\Service\SessionManager:
816
autowire: true
917
autoconfigure: true
@@ -80,10 +88,6 @@ services:
8088
autowire: true
8189
autoconfigure: true
8290

83-
PhpList\Core\Domain\Configuration\Service\Manager\ConfigManager:
84-
autowire: true
85-
autoconfigure: true
86-
8791
PhpList\Core\Domain\Messaging\Service\Manager\BounceRuleManager:
8892
autowire: true
8993
autoconfigure: true

config/services/repositories.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
services:
2+
PhpList\Core\Domain\Configuration\Repository\ConfigRepository:
3+
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
4+
arguments:
5+
- PhpList\Core\Domain\Configuration\Model\Config
6+
7+
PhpList\Core\Domain\Configuration\Repository\EventLogRepository:
8+
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
9+
arguments:
10+
- PhpList\Core\Domain\Configuration\Model\EventLog
11+
212
PhpList\Core\Domain\Identity\Repository\AdministratorRepository:
313
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
414
arguments:
@@ -66,11 +76,6 @@ services:
6676
arguments:
6777
- PhpList\Core\Domain\Messaging\Model\TemplateImage
6878

69-
PhpList\Core\Domain\Configuration\Repository\ConfigRepository:
70-
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
71-
arguments:
72-
- PhpList\Core\Domain\Configuration\Model\Config
73-
7479
PhpList\Core\Domain\Messaging\Repository\UserMessageBounceRepository:
7580
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
7681
arguments:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Model\Filter;
6+
7+
use DateTimeInterface;
8+
use PhpList\Core\Domain\Common\Model\Filter\FilterRequestInterface;
9+
10+
class EventLogFilter implements FilterRequestInterface
11+
{
12+
public function __construct(
13+
private readonly ?string $page = null,
14+
private readonly ?DateTimeInterface $dateFrom = null,
15+
private readonly ?DateTimeInterface $dateTo = null,
16+
) {
17+
}
18+
19+
public function getPage(): ?string
20+
{
21+
return $this->page;
22+
}
23+
24+
public function getDateFrom(): ?DateTimeInterface
25+
{
26+
return $this->dateFrom;
27+
}
28+
29+
public function getDateTo(): ?DateTimeInterface
30+
{
31+
return $this->dateTo;
32+
}
33+
}

src/Domain/Configuration/Repository/EventLogRepository.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,48 @@
44

55
namespace PhpList\Core\Domain\Configuration\Repository;
66

7+
use InvalidArgumentException;
8+
use PhpList\Core\Domain\Common\Model\Filter\FilterRequestInterface;
79
use PhpList\Core\Domain\Common\Repository\AbstractRepository;
810
use PhpList\Core\Domain\Common\Repository\CursorPaginationTrait;
911
use PhpList\Core\Domain\Common\Repository\Interfaces\PaginatableRepositoryInterface;
12+
use PhpList\Core\Domain\Configuration\Model\Filter\EventLogFilter;
13+
use PhpList\Core\Domain\Configuration\Model\EventLog;
1014

1115
class EventLogRepository extends AbstractRepository implements PaginatableRepositoryInterface
1216
{
1317
use CursorPaginationTrait;
18+
19+
/**
20+
* @return EventLog[]
21+
* @throws InvalidArgumentException
22+
*/
23+
public function getFilteredAfterId(int $lastId, int $limit, ?FilterRequestInterface $filter = null): array
24+
{
25+
$queryBuilder = $this->createQueryBuilder('e')
26+
->andWhere('e.id > :lastId')
27+
->setParameter('lastId', $lastId)
28+
->orderBy('e.id', 'ASC')
29+
->setMaxResults($limit);
30+
31+
if ($filter === null) {
32+
return $queryBuilder->getQuery()->getResult();
33+
}
34+
35+
if (!$filter instanceof EventLogFilter) {
36+
throw new InvalidArgumentException('Expected EventLogFilter.');
37+
}
38+
39+
if ($filter->getPage() !== null) {
40+
$queryBuilder->andWhere('e.page = :page')->setParameter('page', $filter->getPage());
41+
}
42+
if ($filter->getDateFrom() !== null) {
43+
$queryBuilder->andWhere('e.entered >= :dateFrom')->setParameter('dateFrom', $filter->getDateFrom());
44+
}
45+
if ($filter->getDateTo() !== null) {
46+
$queryBuilder->andWhere('e.entered <= :dateTo')->setParameter('dateTo', $filter->getDateTo());
47+
}
48+
49+
return $queryBuilder->getQuery()->getResult();
50+
}
1451
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Service\Manager;
6+
7+
use DateTimeImmutable;
8+
use DateTimeInterface;
9+
use PhpList\Core\Domain\Configuration\Model\EventLog;
10+
use PhpList\Core\Domain\Configuration\Model\Filter\EventLogFilter;
11+
use PhpList\Core\Domain\Configuration\Repository\EventLogRepository;
12+
13+
class EventLogManager
14+
{
15+
private EventLogRepository $repository;
16+
17+
public function __construct(EventLogRepository $repository)
18+
{
19+
$this->repository = $repository;
20+
}
21+
22+
public function log(string $page, string $entry): EventLog
23+
{
24+
$log = (new EventLog())
25+
->setEntered(new DateTimeImmutable())
26+
->setPage($page)
27+
->setEntry($entry);
28+
29+
$this->repository->save($log);
30+
31+
return $log;
32+
}
33+
34+
/**
35+
* Get event logs with optional filters (page and date range) and cursor pagination.
36+
*
37+
* @return EventLog[]
38+
*/
39+
public function get(
40+
int $lastId = 0,
41+
int $limit = 50,
42+
?string $page = null,
43+
?DateTimeInterface $dateFrom = null,
44+
?DateTimeInterface $dateTo = null
45+
): array {
46+
$filter = new EventLogFilter($page, $dateFrom, $dateTo);
47+
return $this->repository->getFilteredAfterId($lastId, $limit, $filter);
48+
}
49+
50+
public function delete(EventLog $log): void
51+
{
52+
$this->repository->remove($log);
53+
}
54+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Tests\Unit\Domain\Configuration\Service\Manager;
6+
7+
use DateTimeImmutable;
8+
use PhpList\Core\Domain\Configuration\Model\EventLog;
9+
use PhpList\Core\Domain\Configuration\Model\Filter\EventLogFilter;
10+
use PhpList\Core\Domain\Configuration\Repository\EventLogRepository;
11+
use PhpList\Core\Domain\Configuration\Service\Manager\EventLogManager;
12+
use PHPUnit\Framework\MockObject\MockObject;
13+
use PHPUnit\Framework\TestCase;
14+
15+
final class EventLogManagerTest extends TestCase
16+
{
17+
private EventLogRepository&MockObject $repository;
18+
private EventLogManager $manager;
19+
20+
protected function setUp(): void
21+
{
22+
$this->repository = $this->createMock(EventLogRepository::class);
23+
$this->manager = new EventLogManager($this->repository);
24+
}
25+
26+
public function testLogCreatesAndPersists(): void
27+
{
28+
$this->repository->expects($this->once())
29+
->method('save')
30+
->with($this->isInstanceOf(EventLog::class));
31+
32+
$log = $this->manager->log('dashboard', 'Viewed dashboard');
33+
34+
$this->assertInstanceOf(EventLog::class, $log);
35+
$this->assertSame('dashboard', $log->getPage());
36+
$this->assertSame('Viewed dashboard', $log->getEntry());
37+
$this->assertNotNull($log->getEntered());
38+
$this->assertInstanceOf(DateTimeImmutable::class, $log->getEntered());
39+
}
40+
41+
public function testDelete(): void
42+
{
43+
$log = new EventLog();
44+
$this->repository->expects($this->once())
45+
->method('remove')
46+
->with($log);
47+
48+
$this->manager->delete($log);
49+
}
50+
51+
public function testGetWithFiltersDelegatesToRepository(): void
52+
{
53+
$expected = [new EventLog(), new EventLog()];
54+
55+
$this->repository->expects($this->once())
56+
->method('getFilteredAfterId')
57+
->with(
58+
100,
59+
25,
60+
$this->callback(function (EventLogFilter $filter) {
61+
// Use getters to validate
62+
return method_exists($filter, 'getPage')
63+
&& $filter->getPage() === 'settings'
64+
&& $filter->getDateFrom() instanceof DateTimeImmutable
65+
&& $filter->getDateTo() instanceof DateTimeImmutable
66+
&& $filter->getDateFrom() <= $filter->getDateTo();
67+
})
68+
)
69+
->willReturn($expected);
70+
71+
$from = new DateTimeImmutable('-2 days');
72+
$to = new DateTimeImmutable('now');
73+
$result = $this->manager->get(lastId: 100, limit: 25, page: 'settings', dateFrom: $from, dateTo: $to);
74+
75+
$this->assertSame($expected, $result);
76+
}
77+
78+
public function testGetWithoutFiltersDefaults(): void
79+
{
80+
$expected = [];
81+
82+
$this->repository->expects($this->once())
83+
->method('getFilteredAfterId')
84+
->with(
85+
0,
86+
50,
87+
$this->anything()
88+
)
89+
->willReturn($expected);
90+
91+
$result = $this->manager->get();
92+
$this->assertSame($expected, $result);
93+
}
94+
}

0 commit comments

Comments
 (0)