Skip to content
Open

Dev #384

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/parameters.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ parameters:
env(REST_API_BASE_URL): 'http://api.phplist.local/api/v2'
app.frontend_base_url: '%%env(FRONT_END_BASE_URL)%%'
env(FRONT_END_BASE_URL): 'http://frontend.phplist.local'
parallel_use_with_phplist3: '%%env(parallel_use_with_phplist3)%%'
env(parallel_use_with_phplist3): '0'

# Email configuration
app.mailer_from: '%%env(MAILER_FROM)%%'
Expand Down
8 changes: 8 additions & 0 deletions config/services/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ services:
autoconfigure: true
public: true

PhpList\Core\Domain\Subscription\Service\SubscribePageConfigMigrationService:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Subscription\Service\Manager\SubscribePageManager:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\MessageProcessingPreparator:
autowire: true
autoconfigure: true
Expand Down
27 changes: 22 additions & 5 deletions src/Domain/Configuration/Service/Provider/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpList\Core\Domain\Configuration\Model\ConfigOption;
use PhpList\Core\Domain\Configuration\Repository\ConfigRepository;
use Psr\SimpleCache\CacheInterface;
use ValueError;

class ConfigProvider
{
Expand Down Expand Up @@ -71,16 +72,32 @@ public function getValue(ConfigOption $key): ?string
return $this->defaultConfigs->has($key) ? (string) $this->defaultConfigs->get($key)['value'] : null;
}

public function getValueWithNamespace(ConfigOption $key): ?string
public function getValueWithNamespace(ConfigOption|string $key): ?string
{
$full = $this->getValue($key);
if ($key instanceof ConfigOption) {
$full = $this->getValue($key);
$keyValue = $key->value;
} else {
$keyValue = $key;
$cacheKey = 'cfg:' . $keyValue;
$full = $this->cache->get($cacheKey);
if ($full === null) {
$full = $this->configRepository->findValueByItem($keyValue);
$this->cache->set($cacheKey, $full, $this->ttlSeconds);
}
}

if ($full !== null && $full !== '') {
return $full;
}

if (str_contains($key->value, ':')) {
[$parent] = explode(':', $key->value, 2);
$parentKey = ConfigOption::from($parent);
if (str_contains($keyValue, ':')) {
[$parent] = explode(':', $keyValue, 2);
try {
$parentKey = ConfigOption::from($parent);
} catch (ValueError) {
return null;
}

return $this->getValue($parentKey);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down
16 changes: 16 additions & 0 deletions src/Domain/Subscription/Model/SubscribePage.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class SubscribePage implements DomainModel, Identity, OwnableInterface
#[ORM\JoinColumn(name: 'owner', referencedColumnName: 'id', nullable: true)]
private ?Administrator $owner = null;

/** @var SubscribePageData[] */
private array $data = [];

public function getId(): ?int
{
return $this->id;
Expand All @@ -50,6 +53,12 @@ public function getOwner(): ?Administrator
return $this->owner;
}

/** @return SubscribePageData[] */
public function getData(): array
{
return $this->data;
}

public function setTitle(string $title): self
{
$this->title = $title;
Expand All @@ -67,4 +76,11 @@ public function setOwner(?Administrator $owner): self
$this->owner = $owner;
return $this;
}

/** @param SubscribePageData[] $data */
public function setData(array $data): self
{
$this->data = $data;
return $this;
}
}
91 changes: 84 additions & 7 deletions src/Domain/Subscription/Repository/SubscriberPageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace PhpList\Core\Domain\Subscription\Repository;

use PhpList\Core\Domain\Common\Model\Filter\FilterRequestInterface;
use PhpList\Core\Domain\Common\Model\PaginatedResult;
use PhpList\Core\Domain\Common\Repository\AbstractRepository;
use PhpList\Core\Domain\Common\Repository\CursorPaginationTrait;
use PhpList\Core\Domain\Common\Repository\Interfaces\PaginatableRepositoryInterface;
Expand All @@ -14,17 +16,92 @@ class SubscriberPageRepository extends AbstractRepository implements Paginatable
{
use CursorPaginationTrait;

/** @return array{page: SubscribePage, data: SubscribePageData}[] */
public function findPagesWithData(int $pageId): array
public function findPageWithData(int $pageId): ?SubscribePage
{
return $this->createQueryBuilder('p')
->select('p AS page, d AS data')
->from(SubscribePage::class, 'p')
->from(SubscribePageData::class, 'd')
$result = $this->createQueryBuilder('p')
->select('p AS page', 'd AS data')
->leftJoin(
SubscribePageData::class,
'd',
'ON',
'd.id = p.id'
)
->where('p.id = :id')
->andWhere('d.id = p.id')
->setParameter('id', $pageId)
->getQuery()
->getResult();

if ($result === []) {
return null;
}

return $this->loadPageData($result);
}

public function getFilteredAfterId(FilterRequestInterface $filter): PaginatedResult
{
$queryBuilder = $this->createQueryBuilder('p');

$countQb = clone $queryBuilder;
$total = (int) $countQb
->select('COUNT(DISTINCT p.id)')
->getQuery()
->getSingleScalarResult();

$rows = $queryBuilder
->select('p AS page', 'd AS data')
->leftJoin(
SubscribePageData::class,
'd',
'ON',
'd.id = p.id'
)
->andWhere('p.id > :afterId')
->setParameter('afterId', $filter->getLastId())
->orderBy('p.id', 'ASC')
->setMaxResults($filter->getLimit())
->getQuery()
->getResult();

$grouped = [];
foreach ($rows as $row) {
/** @var SubscribePage $page */
$page = $row['page'] ?? null;
$data = $row['data'] ?? null;
if ($page !== null) {
$grouped[$page->getId()][] = $row;
}
if ($data !== null) {
$grouped[$data->getId()][] = ['data' => $data];
}
}

$pages = [];
foreach ($grouped as $group) {
$pages[] = $this->loadPageData($group);
}
Comment thread
TatevikGr marked this conversation as resolved.

return new PaginatedResult(
items: array_values($pages),
total: $total,
limit: $filter->getLimit(),
lastId: $filter->getLastId(),
);
}

private function loadPageData(array $result): SubscribePage
{
/** @var SubscribePage $page */
$page = array_shift($result)['page'];

$data = [];
foreach ($result as $row) {
if (isset($row['data'])) {
$data[] = $row['data'];
}
}
$page->setData($data);

return $page;
}
Comment thread
TatevikGr marked this conversation as resolved.
}
83 changes: 55 additions & 28 deletions src/Domain/Subscription/Service/Manager/SubscribePageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,44 @@
namespace PhpList\Core\Domain\Subscription\Service\Manager;

use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use PhpList\Core\Domain\Identity\Model\Administrator;
use PhpList\Core\Domain\Subscription\Model\SubscribePage;
use PhpList\Core\Domain\Subscription\Model\SubscribePageData;
use PhpList\Core\Domain\Subscription\Repository\SubscriberPageDataRepository;
use PhpList\Core\Domain\Subscription\Repository\SubscriberPageRepository;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\Translation\TranslatorInterface;
use PhpList\Core\Domain\Subscription\Service\SubscribePageConfigMigrationService;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class SubscribePageManager
{
public function __construct(
private readonly SubscriberPageRepository $pageRepository,
private readonly SubscriberPageDataRepository $pageDataRepository,
private readonly SubscribePageConfigMigrationService $configMigrationService,
private readonly EntityManagerInterface $entityManager,
private readonly TranslatorInterface $translator,
#[Autowire('%parallel_use_with_phplist3%')]
private readonly bool $parallelUseWithPhpList3,
) {
}

public function findPage(int $id): ?SubscribePage
{
$page = $this->pageRepository->findPageWithData($id);
if ($page === null) {
return null;
}

if ($this->parallelUseWithPhpList3) {
$changed = $this->configMigrationService->copyToPageData($page);
if ($changed) {
$page = $this->pageRepository->findPageWithData($id) ?? $page;
}
}

return $page;
}

public function createPage(string $title, bool $active = false, ?Administrator $owner = null): SubscribePage
{
$page = new SubscribePage();
Expand All @@ -35,15 +55,39 @@ public function createPage(string $title, bool $active = false, ?Administrator $
return $page;
}

public function getPage(int $id): SubscribePage
public function syncPageData(array $data, SubscribePage $page): void
{
/** @var SubscribePage|null $page */
$page = $this->pageRepository->find($id);
if (!$page) {
throw new NotFoundHttpException($this->translator->trans('Subscribe page not found'));
if ($page->getId() === null) {
throw new LogicException('Page must be persisted before syncing data');
}
$existingPageData = [];
foreach ($this->getPageData($page) as $pageData) {
$existingPageData[$pageData->getName()] = $pageData;
}

return $page;
foreach ($data as $pageDataKey => $value) {
if (isset($existingPageData[$pageDataKey])) {
$pageData = $existingPageData[$pageDataKey];
$pageData->setData($value);
unset($existingPageData[$pageDataKey]);
continue;
}

$pageData = (new SubscribePageData())
->setId($page->getId())
->setName($pageDataKey)
->setData($value);

$this->pageDataRepository->persist($pageData);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

foreach ($existingPageData as $pageData) {
$this->entityManager->remove($pageData);
}

if ($this->parallelUseWithPhpList3) {
$this->configMigrationService->copyToConfig(page: $page, data: $data);
}
}

public function updatePage(
Expand Down Expand Up @@ -76,25 +120,8 @@ public function deletePage(SubscribePage $page): void
}

/** @return SubscribePageData[] */
public function getPageData(SubscribePage $page): array
private function getPageData(SubscribePage $page): array
{
return $this->pageDataRepository->getByPage($page,);
}

public function setPageData(SubscribePage $page, string $name, ?string $value): SubscribePageData
{
/** @var SubscribePageData|null $data */
$data = $this->pageDataRepository->findByPageAndName($page, $name);

if (!$data) {
$data = (new SubscribePageData())
->setId((int)$page->getId())
->setName($name);
$this->entityManager->persist($data);
}

$data->setData($value);

return $data;
return $this->pageDataRepository->getByPage($page);
}
}
Loading
Loading