-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from mateuszbieniek/page-fieldtype-cleanup-command
Implement 'page-fieldtype-cleanup' command
- Loading branch information
Showing
7 changed files
with
263 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command; | ||
|
||
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; | ||
use Symfony\Component\Console\Style\SymfonyStyle; | ||
|
||
class PageFieldTypeCleanupCommand extends Command | ||
{ | ||
const PAGE_LIMIT = 100; | ||
|
||
/** @var \Symfony\Component\Console\Style\SymfonyStyle */ | ||
private $io; | ||
|
||
/** @var Gateway */ | ||
private $gateway; | ||
|
||
public function __construct(Gateway $gateway) | ||
{ | ||
$this->gateway = $gateway; | ||
|
||
parent::__construct(); | ||
} | ||
|
||
protected function configure(): void | ||
{ | ||
$this | ||
->setName('ezplatform:page-fieldtype-cleanup') | ||
->setDescription( | ||
'This command allows you to search your database for orphaned page fieldtype related records | ||
and clean them up.' | ||
) | ||
->setHelp( | ||
<<<EOT | ||
The command <info>%command.name%</info> allows you to check your database for orphaned records related to the Page Fieldtype | ||
and clean those records if chosen to do so. | ||
After running command it is recommended to regenerate URL aliases, clear persistence cache and reindex. | ||
!As the script directly modifies the Database always perform a backup before running it! | ||
EOT | ||
); | ||
} | ||
|
||
protected function initialize(InputInterface $input, OutputInterface $output): void | ||
{ | ||
$this->io = new SymfonyStyle($input, $output); | ||
|
||
parent::initialize($input, $output); | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output): int | ||
{ | ||
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->gateway->connection->getDatabase()) | ||
); | ||
|
||
$this->io->warning('Always perform the database backup before running this command!'); | ||
|
||
if (!$this->io->confirm( | ||
'Are you sure that you want to proceed and that you have created the database backup?', | ||
false) | ||
) { | ||
return 0; | ||
} | ||
|
||
if ($this->countOrphanedPageRelations() <= 0) { | ||
return 0; | ||
} | ||
|
||
$this->deleteOrphanedPageRelations(); | ||
|
||
$this->io->success('Done'); | ||
|
||
return 0; | ||
} | ||
|
||
private function countOrphanedPageRelations(): int | ||
{ | ||
$count = $this->gateway->countOrphanedPageRelations(); | ||
|
||
$count <= 0 | ||
? $this->io->success('Found: 0') | ||
: $this->io->caution(sprintf('Found: %d orphaned pages', $count)); | ||
|
||
return $count; | ||
} | ||
|
||
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 | ||
in first iteration is equal to %d.', self::PAGE_LIMIT), | ||
false) | ||
) { | ||
return; | ||
} | ||
|
||
$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->gateway->removePage((int) $records[$i]); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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']); | ||
} | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |