Skip to content

Commit

Permalink
Separate PageFieldTypeGateway from the command
Browse files Browse the repository at this point in the history
  • Loading branch information
barw4 committed Jan 12, 2021
1 parent 5ce6c9f commit d4bcacd
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 99 deletions.
19 changes: 7 additions & 12 deletions src/bundle/Command/DatabaseHealthCheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

namespace MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command;

use Doctrine\DBAL\Connection;
use eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider;
use eZ\Publish\API\Repository\ContentService;
use eZ\Publish\API\Repository\LocationService;
use eZ\Publish\API\Repository\PermissionResolver;
Expand Down Expand Up @@ -59,18 +57,14 @@ class DatabaseHealthCheckCommand extends Command
/** @var \Symfony\Component\Console\Style\SymfonyStyle */
private $io;

/** @var \eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider */
private $repositoryConfigurationProvider;

public function __construct(
ContentGateway $contentGateway,
ContentService $contentService,
LocationService $locationService,
SiteAccess $siteAccess,
PermissionResolver $permissionResolver,
Handler $handler,
Repository $repository,
Connection $connection
Repository $repository
) {
$this->contentGateway = $contentGateway;
$this->contentService = $contentService;
Expand All @@ -79,7 +73,6 @@ public function __construct(
$this->permissionResolver = $permissionResolver;
$this->persistenceHandler = $handler;
$this->repository = $repository;
$this->connection = $connection;

parent::__construct();
}
Expand Down Expand Up @@ -128,27 +121,27 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
parent::initialize($input, $output);
}

protected function execute(InputInterface $input, OutputInterface $output): void
protected function execute(InputInterface $input, OutputInterface $output): ?int
{
$this->io->title('eZ Platform Database Health Checker');
$this->io->text(
sprintf('Using database: <info>%s</info>', $this->connection->getDatabase())
sprintf('Using database: <info>%s</info>', $this->contentGateway->connection->getDatabase())
);

$this->io->warning(
'Fixing corruption will modify your database! Always perform the database backup before running this command!'
);

if (!$this->io->confirm('Are you sure that you want to proceed?', false)) {
return;
return 0;
}

if ($this->siteAccess->name !== 'db-checker') {
if (!$this->io->confirm(
'It is recommended to run this command in "db-checker" SiteAccess. Are you sure that you want ' .
'to continue?',
false)) {
return;
return 0;
}
}

Expand All @@ -161,6 +154,8 @@ protected function execute(InputInterface $input, OutputInterface $output): void
$this->checkDuplicatedAttributes();

$this->io->success('Done');

return 0;
}

private function checkContentWithoutAttributes(InputInterface $input, OutputInterface $output)
Expand Down
101 changes: 18 additions & 83 deletions src/bundle/Command/PageFieldTypeCleanupCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

namespace MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\FetchMode;
use EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\Gateway;
use MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\PageFieldTypeGatewayInterface as Gateway;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -16,19 +14,15 @@ class PageFieldTypeCleanupCommand extends Command
{
const PAGE_LIMIT = 100;

/** @var \Doctrine\DBAL\Connection */
private $connection;

/** @var \EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\Gateway|null */
private $pageFieldTypeGateway;

/** @var \Symfony\Component\Console\Style\SymfonyStyle */
private $io;

public function __construct(Connection $connection, ?Gateway $pageFieldTypeGateway = null)
/** @var Gateway */
private $gateway;

public function __construct(Gateway $gateway)
{
$this->connection = $connection;
$this->pageFieldTypeGateway = $pageFieldTypeGateway;
$this->gateway = $gateway;

parent::__construct();
}
Expand Down Expand Up @@ -63,15 +57,15 @@ protected function initialize(InputInterface $input, OutputInterface $output): v

protected function execute(InputInterface $input, OutputInterface $output): int
{
if ($this->pageFieldTypeGateway === null) {
if ($this->gateway->pageFieldTypeGateway === null) {
$this->io->warning('Page FieldType bundle is missing. Cannot continue.');

return 0;
}

$this->io->title('eZ Platform Database Health Checker');
$this->io->text(
sprintf('Using database: <info>%s</info>', $this->connection->getDatabase())
sprintf('Using database: <info>%s</info>', $this->gateway->connection->getDatabase())
);

$this->io->warning('Always perform the database backup before running this command!');
Expand All @@ -83,48 +77,29 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 0;
}

if (!$this->countOrphanedPages() > 0) {
if ($this->countOrphanedPageRelations() <= 0) {
return 0;
}

$this->deleteOrphanedPagesRelations();
$this->deleteOrphanedPageRelations();

$this->io->success('Done');

return 0;
}

private function countOrphanedPages(): int
private function countOrphanedPageRelations(): int
{
$pagesQuery = $this->connection->createQueryBuilder();
$pagesQuery = $pagesQuery->select('id')
->from('ezpage_pages')
->getSQL();

$countQuery = $this->connection->createQueryBuilder();
$countQuery->select('COUNT(page_id)')
->from('ezpage_map_zones_pages', 'p')
->where(
$countQuery->expr()->notIn(
'page_id',
$pagesQuery
)
);

$count = (int) $countQuery->execute()->fetch(FetchMode::NUMERIC)[0];
$count = $this->gateway->countOrphanedPageRelations();

if ($count <= 0) {
$this->io->success('Found: 0');

return $count;
}

$this->io->caution(sprintf('Found: %d orphaned pages', $count));
$count <= 0
? $this->io->success('Found: 0')
: $this->io->caution(sprintf('Found: %d orphaned pages', $count));

return $count;
}

private function deleteOrphanedPagesRelations(): void
private function deleteOrphanedPageRelations(): void
{
if (!$this->io->confirm(
sprintf('Are you sure that you want to proceed? The maximum number of pages that will be cleaned
Expand All @@ -134,54 +109,14 @@ private function deleteOrphanedPagesRelations(): void
return;
}

$pagesQuery = $this->connection->createQueryBuilder();
$pagesQuery = $pagesQuery->select('id')
->from('ezpage_pages')
->getSQL();

$orphanedPagesQuery = $this->connection->createQueryBuilder();
$orphanedPagesQuery->select('page_id')
->from('ezpage_map_zones_pages', 'p')
->where(
$orphanedPagesQuery->expr()->notIn(
'page_id',
$pagesQuery
)
)
->setMaxResults(self::PAGE_LIMIT);

$records = $orphanedPagesQuery->execute()->fetchAll(FetchMode::COLUMN);
$records = $this->gateway->getOrphanedPageRelations(self::PAGE_LIMIT);

$progressBar = $this->io->createProgressBar(count($records));

for ($i = 0; $i < self::PAGE_LIMIT; ++$i) {
if (isset($records[$i])) {
$progressBar->advance(1);
$this->removePage((int) $records[$i]);
}
}
}

private function removePage(int $pageId): void
{
$removedBlocks = [];
$removedZones = [];

foreach ($this->pageFieldTypeGateway->loadAttributesAssignedToPage($pageId) as $attribute) {
$this->pageFieldTypeGateway->unassignAttributeFromBlock((int) $attribute['id'], (int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeAttribute((int) $attribute['id']);

if (!\in_array($attribute['block_id'], $removedBlocks, true)) {
$this->pageFieldTypeGateway->unassignBlockFromZone((int) $attribute['block_id'], (int) $attribute['zone_id']);
$this->pageFieldTypeGateway->removeBlock((int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeBlockDesign((int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeBlockVisibility((int) $attribute['block_id']);
$removedBlocks[] = $attribute['block_id'];
}

if (!\in_array($attribute['zone_id'], $removedZones, true)) {
$this->pageFieldTypeGateway->unassignZoneFromPage((int) $attribute['zone_id'], $pageId);
$this->pageFieldTypeGateway->removeZone((int) $attribute['zone_id']);
$this->gateway->removePage((int) $records[$i]);
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/bundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ services:
$locationGateway: '@ezpublish.persistence.legacy.location.gateway'
$fieldHandler: '@ezpublish.persistence.legacy.field_handler'

MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\PageFieldTypeDoctrineDatabase:
arguments:
$connection: '@ezpublish.persistence.connection'
$pageFieldTypeGateway: '@?EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\DoctrineGateway'

MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command\DatabaseHealthCheckCommand:
arguments:
$contentGateway: '@MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\DoctrineDatabase'
Expand All @@ -15,14 +20,12 @@ services:
$permissionResolver: '@eZ\Publish\API\Repository\PermissionResolver'
$handler: '@ezpublish.api.storage_engine'
$repository: '@ezpublish.api.repository'
$connection: '@ezpublish.persistence.connection'
tags:
- { name: 'console.command', command: 'ezplatform:database-health-check' }

MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command\PageFieldTypeCleanupCommand:
arguments:
$connection: '@ezpublish.persistence.connection'
$pageFieldTypeGateway: '@?EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\DoctrineGateway'
$gateway: '@MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\PageFieldTypeDoctrineDatabase'
tags:
- { name: 'console.command', command: 'ezplatform:page-fieldtype-cleanup' }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class DoctrineDatabase implements GatewayInterface
/**
* @var \Doctrine\DBAL\Connection
*/
protected $connection;
public $connection;

/**
* @var ContentGateway
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\FetchMode;
use EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\Gateway;

class PageFieldTypeDoctrineDatabase implements PageFieldTypeGatewayInterface
{
/** @var \Doctrine\DBAL\Connection */
public $connection;

/** @var \EzSystems\EzPlatformPageFieldType\FieldType\Page\Storage\Gateway|null */
public $pageFieldTypeGateway;

public function __construct(Connection $connection, ?Gateway $pageFieldTypeGateway = null)
{
$this->connection = $connection;
$this->pageFieldTypeGateway = $pageFieldTypeGateway;
}

public function countOrphanedPageRelations(): int
{
$pagesQuery = $this->connection->createQueryBuilder();
$pagesQuery = $pagesQuery->select('id')
->from('ezpage_pages')
->getSQL();

$countQuery = $this->connection->createQueryBuilder();
$countQuery->select('COUNT(page_id)')
->from('ezpage_map_zones_pages', 'p')
->where(
$countQuery->expr()->notIn(
'page_id',
$pagesQuery
)
);

return (int) $countQuery->execute()->fetch(FetchMode::NUMERIC)[0];
}

public function getOrphanedPageRelations(int $limit): array
{
$pagesQuery = $this->connection->createQueryBuilder();
$pagesQuery = $pagesQuery->select('id')
->from('ezpage_pages')
->getSQL();

$orphanedPagesQuery = $this->connection->createQueryBuilder();
$orphanedPagesQuery->select('page_id')
->from('ezpage_map_zones_pages', 'p')
->where(
$orphanedPagesQuery->expr()->notIn(
'page_id',
$pagesQuery
)
)
->setMaxResults($limit);

return $orphanedPagesQuery->execute()->fetchAll(FetchMode::COLUMN);
}

public function removePage(int $pageId): void
{
$removedBlocks = [];
$removedZones = [];

foreach ($this->pageFieldTypeGateway->loadAttributesAssignedToPage($pageId) as $attribute) {
$this->pageFieldTypeGateway->unassignAttributeFromBlock((int) $attribute['id'], (int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeAttribute((int) $attribute['id']);

if (!\in_array($attribute['block_id'], $removedBlocks, true)) {
$this->pageFieldTypeGateway->unassignBlockFromZone((int) $attribute['block_id'], (int) $attribute['zone_id']);
$this->pageFieldTypeGateway->removeBlock((int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeBlockDesign((int) $attribute['block_id']);
$this->pageFieldTypeGateway->removeBlockVisibility((int) $attribute['block_id']);
$removedBlocks[] = $attribute['block_id'];
}

if (!\in_array($attribute['zone_id'], $removedZones, true)) {
$this->pageFieldTypeGateway->unassignZoneFromPage((int) $attribute['zone_id'], $pageId);
$this->pageFieldTypeGateway->removeZone((int) $attribute['zone_id']);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway;

interface PageFieldTypeGatewayInterface
{
public function countOrphanedPageRelations(): int;

public function getOrphanedPageRelations(int $limit): array;
}

0 comments on commit d4bcacd

Please sign in to comment.