From 3405afd621da2176e8df6dd4c3d276d0375f9c23 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Wed, 12 Jan 2022 12:41:28 +0100 Subject: [PATCH 1/3] extend page-fieldtype-cleanup command to remove leftovers --- .../Command/PageFieldTypeCleanupCommand.php | 44 ++++++- .../Gateway/PageFieldTypeDoctrineDatabase.php | 120 ++++++++++++++++++ .../Gateway/PageFieldTypeGatewayInterface.php | 16 +++ 3 files changed, 176 insertions(+), 4 deletions(-) diff --git a/src/bundle/Command/PageFieldTypeCleanupCommand.php b/src/bundle/Command/PageFieldTypeCleanupCommand.php index 6de1df4..fa9c2bd 100644 --- a/src/bundle/Command/PageFieldTypeCleanupCommand.php +++ b/src/bundle/Command/PageFieldTypeCleanupCommand.php @@ -90,10 +90,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $limit = (int) $helper->ask($input, $output, $question); - if ($this->countOrphanedPageRelations() <= 0) { - return 0; - } - $this->deleteOrphanedPageRelations($limit); $this->io->success('Done'); @@ -132,5 +128,45 @@ private function deleteOrphanedPageRelations(int $limit): void $this->gateway->removePage((int) $records[$i]); } } + + $this->io->info('Orphaned blocks and related items which cannot be deleted using the standard procedure will be cleared up now.'); + + $orphanedBlocks = $this->gateway->getOrphanedBlockIds($limit); + + $this->io->caution(sprintf('Found %d orphaned blocks within the chosen limit.', count($orphanedBlocks))); + + $orphanedAttributes = $this->gateway->getOrphanedAttributeIds($orphanedBlocks); + + $this->io->caution( + sprintf('Found %d orphaned attributes related to the found blocks.', count($orphanedAttributes)) + ); + + $progressBar = $this->io->createProgressBar(6); + + $this->io->info('Removing orphaned ezpage_map_attributes_blocks records'); + $this->gateway->removeOrphanedBlockAttributes($orphanedAttributes); + $progressBar->advance(); + + $this->io->info('Removing orphaned ezpage_attributes records'); + $this->gateway->removeOrphanedAttributes($orphanedAttributes); + $progressBar->advance(); + + $this->io->info('Removing orphaned ezpage_blocks_design records'); + $this->gateway->removeOrphanedBlockDesigns($orphanedBlocks); + $progressBar->advance(); + + $this->io->info('Removing orphaned ezpage_blocks_visibility records'); + $this->gateway->removeOrphanedBlockVisibilities($orphanedBlocks); + $progressBar->advance(); + + $this->io->info('Removing orphaned ezpage_blocks records'); + $this->gateway->removeOrphanedBlocks($orphanedBlocks); + $progressBar->advance(); + + $this->io->info('Removing orphaned ezpage_map_blocks_zones records'); + $this->gateway->removeOrphanedBlocksZones($orphanedBlocks); + $progressBar->advance(); + + $this->io->newLine(); } } diff --git a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php index c26b025..ce993bf 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php @@ -91,4 +91,124 @@ public function removePage(int $pageId): void $this->pageFieldTypeGateway->removeZone((int) $zone['id']); } } + + public function getOrphanedBlockIds(int $limit): array + { + $zonesQuery = $this->connection->createQueryBuilder(); + $zonesQuery = $zonesQuery->select('id') + ->from('ezpage_zones') + ->getSQL(); + + $orphanedBlocksQuery = $this->connection->createQueryBuilder(); + $orphanedBlocksQuery->select('block_id') + ->from('ezpage_map_blocks_zones', 'bz') + ->where( + $orphanedBlocksQuery->expr()->notIn( + 'zone_id', + $zonesQuery + ) + ) + ->setMaxResults($limit); + + return $orphanedBlocksQuery->execute()->fetchAll(FetchMode::COLUMN); + } + + public function getOrphanedAttributeIds(array $blockIds): array + { + $orphanedAttributesQuery = $this->connection->createQueryBuilder(); + $orphanedAttributesQuery->select('attribute_id') + ->from('ezpage_map_attributes_blocks') + ->where( + $orphanedAttributesQuery->expr()->in( + 'block_id', + $orphanedAttributesQuery->createPositionalParameter($blockIds, Connection::PARAM_INT_ARRAY) + ) + ); + + return $orphanedAttributesQuery->execute()->fetchAll(FetchMode::COLUMN); + } + + public function removeOrphanedBlockAttributes(array $attributeIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_map_attributes_blocks') + ->where( + $query->expr()->in( + 'attribute_id', + $query->createPositionalParameter($attributeIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } + + public function removeOrphanedAttributes(array $attributeIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_attributes') + ->where( + $query->expr()->in( + 'id', + $query->createPositionalParameter($attributeIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } + + public function removeOrphanedBlockDesigns(array $blockIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_blocks_design') + ->where( + $query->expr()->in( + 'block_id', + $query->createPositionalParameter($blockIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } + + public function removeOrphanedBlockVisibilities(array $blockIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_blocks_visibility') + ->where( + $query->expr()->in( + 'block_id', + $query->createPositionalParameter($blockIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } + + public function removeOrphanedBlocksZones(array $blockIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_map_blocks_zones') + ->where( + $query->expr()->in( + 'block_id', + $query->createPositionalParameter($blockIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } + + public function removeOrphanedBlocks(array $blockIds): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete('ezpage_blocks') + ->where( + $query->expr()->in( + 'id', + $query->createPositionalParameter($blockIds, Connection::PARAM_INT_ARRAY) + ) + ); + + $query->execute(); + } } diff --git a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php index 826cbef..9a97b37 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php @@ -9,4 +9,20 @@ interface PageFieldTypeGatewayInterface public function countOrphanedPageRelations(): int; public function getOrphanedPageRelations(int $limit): array; + + public function getOrphanedBlockIds(int $limit): array; + + public function getOrphanedAttributeIds(array $blockIds): array; + + public function removeOrphanedBlockAttributes(array $attributeIds): void; + + public function removeOrphanedAttributes(array $attributeIds): void; + + public function removeOrphanedBlockDesigns(array $blockIds): void; + + public function removeOrphanedBlockVisibilities(array $blockIds): void; + + public function removeOrphanedBlocksZones(array $blockIds): void; + + public function removeOrphanedBlocks(array $blockIds): void; } From ca93f00ff5d6d51bdb2ab11fb5f75dc88ed7aca4 Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Wed, 12 Jan 2022 14:17:01 +0100 Subject: [PATCH 2/3] extended orphaned blocks query, applied review remarks --- .../Command/PageFieldTypeCleanupCommand.php | 79 ++++++++++++------- src/bundle/Resources/config/services.yml | 1 + .../Gateway/PageFieldTypeDoctrineDatabase.php | 58 +++++++++++++- .../Gateway/PageFieldTypeGatewayInterface.php | 25 ++++++ 4 files changed, 135 insertions(+), 28 deletions(-) diff --git a/src/bundle/Command/PageFieldTypeCleanupCommand.php b/src/bundle/Command/PageFieldTypeCleanupCommand.php index fa9c2bd..d6a855f 100644 --- a/src/bundle/Command/PageFieldTypeCleanupCommand.php +++ b/src/bundle/Command/PageFieldTypeCleanupCommand.php @@ -4,6 +4,8 @@ namespace MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command; +use Exception; +use eZ\Publish\API\Repository\Repository; use MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\PageFieldTypeGatewayInterface as Gateway; use Symfony\Bundle\MakerBundle\Validator; use Symfony\Component\Console\Command\Command; @@ -22,9 +24,13 @@ class PageFieldTypeCleanupCommand extends Command /** @var Gateway */ private $gateway; - public function __construct(Gateway $gateway) + /** @var \eZ\Publish\API\Repository\Repository */ + private $repository; + + public function __construct(Gateway $gateway, Repository $repository) { $this->gateway = $gateway; + $this->repository = $repository; parent::__construct(); } @@ -90,7 +96,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $limit = (int) $helper->ask($input, $output, $question); - $this->deleteOrphanedPageRelations($limit); + $count = $this->countOrphanedPageRelations(); + + if ($count) { + $this->deleteOrphanedPageRelations($limit); + } $this->io->success('Done'); @@ -129,44 +139,59 @@ private function deleteOrphanedPageRelations(int $limit): void } } - $this->io->info('Orphaned blocks and related items which cannot be deleted using the standard procedure will be cleared up now.'); + $this->deleteUnrelatedLeftovers($limit); + } + + private function deleteUnrelatedLeftovers(int $limit): void + { + $this->io->info('Orphaned blocks and related items which cannot be deleted using the standard procedure will be searched for now.'); $orphanedBlocks = $this->gateway->getOrphanedBlockIds($limit); + $orphanedAttributes = $this->gateway->getOrphanedAttributeIds($orphanedBlocks); $this->io->caution(sprintf('Found %d orphaned blocks within the chosen limit.', count($orphanedBlocks))); - $orphanedAttributes = $this->gateway->getOrphanedAttributeIds($orphanedBlocks); + $this->io->caution(sprintf('Found %d orphaned attributes related to the found blocks.', count($orphanedAttributes))); - $this->io->caution( - sprintf('Found %d orphaned attributes related to the found blocks.', count($orphanedAttributes)) - ); + if (!$this->io->confirm('Are you sure that you want to proceed? The block-related records will be now removed.', false)) { + return; + } - $progressBar = $this->io->createProgressBar(6); + $this->repository->beginTransaction(); - $this->io->info('Removing orphaned ezpage_map_attributes_blocks records'); - $this->gateway->removeOrphanedBlockAttributes($orphanedAttributes); - $progressBar->advance(); + try { + $progressBar = $this->io->createProgressBar(6); - $this->io->info('Removing orphaned ezpage_attributes records'); - $this->gateway->removeOrphanedAttributes($orphanedAttributes); - $progressBar->advance(); + $this->io->info('Removing orphaned ezpage_map_attributes_blocks records'); + $this->gateway->removeOrphanedBlockAttributes($orphanedAttributes); + $progressBar->advance(); - $this->io->info('Removing orphaned ezpage_blocks_design records'); - $this->gateway->removeOrphanedBlockDesigns($orphanedBlocks); - $progressBar->advance(); + $this->io->info('Removing orphaned ezpage_attributes records'); + $this->gateway->removeOrphanedAttributes($orphanedAttributes); + $progressBar->advance(); - $this->io->info('Removing orphaned ezpage_blocks_visibility records'); - $this->gateway->removeOrphanedBlockVisibilities($orphanedBlocks); - $progressBar->advance(); + $this->io->info('Removing orphaned ezpage_blocks_design records'); + $this->gateway->removeOrphanedBlockDesigns($orphanedBlocks); + $progressBar->advance(); - $this->io->info('Removing orphaned ezpage_blocks records'); - $this->gateway->removeOrphanedBlocks($orphanedBlocks); - $progressBar->advance(); + $this->io->info('Removing orphaned ezpage_blocks_visibility records'); + $this->gateway->removeOrphanedBlockVisibilities($orphanedBlocks); + $progressBar->advance(); - $this->io->info('Removing orphaned ezpage_map_blocks_zones records'); - $this->gateway->removeOrphanedBlocksZones($orphanedBlocks); - $progressBar->advance(); + $this->io->info('Removing orphaned ezpage_blocks records'); + $this->gateway->removeOrphanedBlocks($orphanedBlocks); + $progressBar->advance(); - $this->io->newLine(); + $this->io->info('Removing orphaned ezpage_map_blocks_zones records'); + $this->gateway->removeOrphanedBlocksZones($orphanedBlocks); + $progressBar->advance(); + + $this->io->newLine(); + + $this->repository->commit(); + } catch (Exception $e) { + $this->repository->rollback(); + throw $e; + } } } diff --git a/src/bundle/Resources/config/services.yml b/src/bundle/Resources/config/services.yml index ef04af2..7f2932c 100644 --- a/src/bundle/Resources/config/services.yml +++ b/src/bundle/Resources/config/services.yml @@ -26,6 +26,7 @@ services: MateuszBieniek\EzPlatformDatabaseHealthCheckerBundle\Command\PageFieldTypeCleanupCommand: arguments: $gateway: '@MateuszBieniek\EzPlatformDatabaseHealthChecker\Persistence\Legacy\Content\Gateway\PageFieldTypeDoctrineDatabase' + $repository: '@ezpublish.api.repository' tags: - { name: 'console.command', command: 'ezplatform:page-fieldtype-cleanup' } diff --git a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php index ce993bf..a708f5f 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeDoctrineDatabase.php @@ -92,8 +92,12 @@ public function removePage(int $pageId): void } } + /** + * @inheritDoc + */ public function getOrphanedBlockIds(int $limit): array { + //fetching the first set via ezpage_map_blocks_zones table $zonesQuery = $this->connection->createQueryBuilder(); $zonesQuery = $zonesQuery->select('id') ->from('ezpage_zones') @@ -110,9 +114,43 @@ public function getOrphanedBlockIds(int $limit): array ) ->setMaxResults($limit); - return $orphanedBlocksQuery->execute()->fetchAll(FetchMode::COLUMN); + $firstResult = $orphanedBlocksQuery->execute()->fetchAll(FetchMode::COLUMN); + + //fetching the second set via ezpage_map_zones_pages table + $pagesQuery = $this->connection->createQueryBuilder(); + $pagesQuery = $pagesQuery->select('id') + ->from('ezpage_pages') + ->getSQL(); + + $secondZonesQuery = $this->connection->createQueryBuilder(); + $secondZonesQuery->select('zone_id') + ->from('ezpage_map_zones_pages', 'zp') + ->where( + $secondZonesQuery->expr()->notIn( + 'page_id', + $pagesQuery + ) + ); + + $secondOrphanedBlocksQuery = $this->connection->createQueryBuilder(); + $secondOrphanedBlocksQuery->select('block_id') + ->from('ezpage_map_blocks_zones', 'bz') + ->where( + $secondOrphanedBlocksQuery->expr()->in( + 'zone_id', + $secondZonesQuery->getSQL() + ) + ) + ->setMaxResults($limit); + + $secondResult = $secondOrphanedBlocksQuery->execute()->fetchAll(FetchMode::COLUMN); + + return array_unique(array_merge($firstResult, $secondResult)); } + /** + * @inheritDoc + */ public function getOrphanedAttributeIds(array $blockIds): array { $orphanedAttributesQuery = $this->connection->createQueryBuilder(); @@ -128,6 +166,9 @@ public function getOrphanedAttributeIds(array $blockIds): array return $orphanedAttributesQuery->execute()->fetchAll(FetchMode::COLUMN); } + /** + * @inheritDoc + */ public function removeOrphanedBlockAttributes(array $attributeIds): void { $query = $this->connection->createQueryBuilder(); @@ -142,6 +183,9 @@ public function removeOrphanedBlockAttributes(array $attributeIds): void $query->execute(); } + /** + * @inheritDoc + */ public function removeOrphanedAttributes(array $attributeIds): void { $query = $this->connection->createQueryBuilder(); @@ -156,6 +200,9 @@ public function removeOrphanedAttributes(array $attributeIds): void $query->execute(); } + /** + * @inheritDoc + */ public function removeOrphanedBlockDesigns(array $blockIds): void { $query = $this->connection->createQueryBuilder(); @@ -170,6 +217,9 @@ public function removeOrphanedBlockDesigns(array $blockIds): void $query->execute(); } + /** + * @inheritDoc + */ public function removeOrphanedBlockVisibilities(array $blockIds): void { $query = $this->connection->createQueryBuilder(); @@ -184,6 +234,9 @@ public function removeOrphanedBlockVisibilities(array $blockIds): void $query->execute(); } + /** + * @inheritDoc + */ public function removeOrphanedBlocksZones(array $blockIds): void { $query = $this->connection->createQueryBuilder(); @@ -198,6 +251,9 @@ public function removeOrphanedBlocksZones(array $blockIds): void $query->execute(); } + /** + * @inheritDoc + */ public function removeOrphanedBlocks(array $blockIds): void { $query = $this->connection->createQueryBuilder(); diff --git a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php index 9a97b37..9b04c35 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/PageFieldTypeGatewayInterface.php @@ -10,19 +10,44 @@ public function countOrphanedPageRelations(): int; public function getOrphanedPageRelations(int $limit): array; + /** + * @return int[] + */ public function getOrphanedBlockIds(int $limit): array; + /** + * @param int[] $blockIds + * @return int[] + */ public function getOrphanedAttributeIds(array $blockIds): array; + /** + * @param int[] $attributeIds + */ public function removeOrphanedBlockAttributes(array $attributeIds): void; + /** + * @param int[] $attributeIds + */ public function removeOrphanedAttributes(array $attributeIds): void; + /** + * @param int[] $blockIds + */ public function removeOrphanedBlockDesigns(array $blockIds): void; + /** + * @param int[] $blockIds + */ public function removeOrphanedBlockVisibilities(array $blockIds): void; + /** + * @param int[] $blockIds + */ public function removeOrphanedBlocksZones(array $blockIds): void; + /** + * @param int[] $blockIds + */ public function removeOrphanedBlocks(array $blockIds): void; } From e61aed4423a81b16ca6be6e91d56f2c9e5ca7d1e Mon Sep 17 00:00:00 2001 From: Bartek Wajda Date: Wed, 12 Jan 2022 14:36:47 +0100 Subject: [PATCH 3/3] minor update --- src/bundle/Command/PageFieldTypeCleanupCommand.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/bundle/Command/PageFieldTypeCleanupCommand.php b/src/bundle/Command/PageFieldTypeCleanupCommand.php index d6a855f..18a0a20 100644 --- a/src/bundle/Command/PageFieldTypeCleanupCommand.php +++ b/src/bundle/Command/PageFieldTypeCleanupCommand.php @@ -96,33 +96,29 @@ protected function execute(InputInterface $input, OutputInterface $output): int $limit = (int) $helper->ask($input, $output, $question); - $count = $this->countOrphanedPageRelations(); - - if ($count) { - $this->deleteOrphanedPageRelations($limit); - } + $this->countOrphanedPageRelations(); + $this->deleteOrphanedPageRelations($limit); $this->io->success('Done'); return 0; } - private function countOrphanedPageRelations(): int + private function countOrphanedPageRelations(): void { $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(int $limit): void { if (!$this->io->confirm( sprintf('Are you sure that you want to proceed? The maximum number of pages that will be cleaned - in this iteration is equal to %d.', $limit), + in this iteration is equal to %d. If the number is equal to 0 you can still continue to run the remaining + cleaning methods.', $limit), false) ) { return;