From aaf8d6e49a4ecbaefc92519bdc3272a5ef2e6a65 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Wed, 29 Aug 2018 14:50:37 +0200 Subject: [PATCH 01/13] As an Administrator I want to have a CLI command for database cleanup --- .../Command/RemoveVersionsCommand.php | 198 ++++++++++++++++++ .../Resources/config/services.yml | 6 + 2 files changed, 204 insertions(+) create mode 100644 eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php new file mode 100644 index 00000000000..d169c9de35e --- /dev/null +++ b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php @@ -0,0 +1,198 @@ +userService = $userService; + $this->contentService = $contentService; + $this->permissionResolver = $permissionResolver; + $this->connection = $connection; + + parent::__construct(); + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + parent::initialize($input, $output); + + $this->permissionResolver->setCurrentUserReference( + $this->userService->loadUserByLogin($input->getOption('user')) + ); + } + + protected function configure(): void + { + $this + ->setName('ezplatform:remove-versions') + ->setDescription('Remove unwanted content versions. It keeps published version untouched. By default, it keeps also the last archived/draft version.') + ->addOption( + 'status', + 's', + InputOption::VALUE_OPTIONAL, + sprintf( + "Select which version types should be removed: '%s', '%s', '%s'.", + self::VERSION_DRAFT, + self::VERSION_ARCHIVED, + self::VERSION_ALL + ), + self::VERSION_ALL + ) + ->addOption( + 'keep', + 'k', + InputOption::VALUE_OPTIONAL, + "Sets number of the most recent versions (both drafts and archived) which won't be removed.", + self::DEFAULT_KEEP + ) + ->addOption( + 'user', + 'u', + InputOption::VALUE_OPTIONAL, + 'eZ Platform username (with Role containing at least Content policies: remove, read, versionread)', + self::DEFAULT_REPOSITORY_USER + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): void + { + $contentIds = $this->getObjectsIds((int) $input->getOption('keep'), $input->getOption('status')); + $contentIdsCount = count($contentIds); + + if ($contentIdsCount === 0) { + $output->writeln('There is no Contents matching given criteria.'); + + return; + } + + $output->writeln(sprintf( + 'Found %d Content IDs matching given criteria.', + $contentIdsCount + )); + + $removedVersionsCounter = 0; + + foreach ($contentIds as $contentData) { + try { + $contentInfo = $this->contentService->loadContentInfo($contentData['id']); + $versions = $this->contentService->loadVersions($contentInfo); + $versionsCount = \count($versions); + + $output->writeln(sprintf( + 'Content %d has %d version(s)', + $contentData['id'], + $versionsCount + ), Output::VERBOSITY_VERBOSE); + + $versions = array_slice(array_reverse($versions), (int) $input->getOption('keep')); + + foreach ($versions as $version) { + if ( + (!$version->isPublished() && $input->getOption('status') === self::VERSION_ALL) || + ($version->isDraft() && $input->getOption('status') === self::VERSION_DRAFT) || + ($version->isArchived() && $input->getOption('status') === self::VERSION_ARCHIVED) + ) { + $this->contentService->deleteVersion($version); + ++$removedVersionsCounter; + $output->writeln(sprintf( + "Content's (%s) version (%s) has been deleted.", + $contentInfo->id, + $version->id + ), Output::VERBOSITY_VERBOSE); + } + } + } catch (\Exception $e) { + $output->writeln(sprintf( + '%s', + $e->getMessage() + )); + } + } + + $output->writeln(sprintf( + 'Removed %d unwanted contents version(s).', + $removedVersionsCounter + )); + } + + protected function getObjectsIds(int $keep, string $status): array + { + $query = $this->connection->createQueryBuilder() + ->select('c.id, v.status') + ->from('ezcontentobject', 'c') + ->leftJoin('c', 'ezcontentobject_version', 'v', 'v.contentobject_id = c.id') + ->groupBy('c.id', 'v.status') + ->having('count(c.id) > :keep'); + $query->setParameter('keep', $keep); + + if ($status === self::VERSION_DRAFT || $status === self::VERSION_ARCHIVED) { + $query->where('v.status = :status'); + $query->setParameter('status', $this->getVersionInfoStatus($status)); + } + + $stmt = $query->execute(); + + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + private function getVersionInfoStatus(string $status): ?int + { + if ($status === self::VERSION_ARCHIVED) { + return VersionInfo::STATUS_ARCHIVED; + } + if ($status === self::VERSION_DRAFT) { + return VersionInfo::STATUS_DRAFT; + } + } +} diff --git a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml index a1a16ec1e52..94c1160276b 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml +++ b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml @@ -230,3 +230,9 @@ services: class: eZ\Publish\Core\MVC\Symfony\Translation\ValidationErrorFileVisitor tags: - { name: jms_translation.file_visitor, alias: ez_validation_error } + + ezplatform.core.command.remove_versions: + class: eZ\Bundle\EzPublishCoreBundle\Command\RemoveVersionsCommand + arguments: + - "@ezpublish.api.inner_repository" + - "@ezpublish.persistence.connection" From 6bf283d6879860b4ea5793535a60ccde18a4578a Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Tue, 4 Sep 2018 11:40:18 +0200 Subject: [PATCH 02/13] fixup! As an Administrator I want to have a CLI command for database cleanup --- .../Command/RemoveVersionsCommand.php | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php index d169c9de35e..13fee013e7d 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php @@ -9,10 +9,12 @@ namespace eZ\Bundle\EzPublishCoreBundle\Command; use Doctrine\DBAL\Connection; +use Exception; use eZ\Publish\API\Repository\ContentService; use eZ\Publish\API\Repository\PermissionResolver; use eZ\Publish\API\Repository\UserService; use eZ\Publish\API\Repository\Values\Content\VersionInfo; +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; use PDO; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -107,7 +109,10 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): void { - $contentIds = $this->getObjectsIds((int) $input->getOption('keep'), $input->getOption('status')); + $keep = (int) $input->getOption('keep'); + $status = $input->getOption('status'); + + $contentIds = $this->getObjectsIds($keep, $status); $contentIdsCount = count($contentIds); if ($contentIdsCount === 0) { @@ -127,7 +132,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void try { $contentInfo = $this->contentService->loadContentInfo($contentData['id']); $versions = $this->contentService->loadVersions($contentInfo); - $versionsCount = \count($versions); + $versionsCount = count($versions); $output->writeln(sprintf( 'Content %d has %d version(s)', @@ -135,13 +140,13 @@ protected function execute(InputInterface $input, OutputInterface $output): void $versionsCount ), Output::VERBOSITY_VERBOSE); - $versions = array_slice(array_reverse($versions), (int) $input->getOption('keep')); + $versions = array_slice(array_reverse($versions), $keep); foreach ($versions as $version) { if ( - (!$version->isPublished() && $input->getOption('status') === self::VERSION_ALL) || - ($version->isDraft() && $input->getOption('status') === self::VERSION_DRAFT) || - ($version->isArchived() && $input->getOption('status') === self::VERSION_ARCHIVED) + (!$version->isPublished() && $status === self::VERSION_ALL) || + ($version->isDraft() && $status === self::VERSION_DRAFT) || + ($version->isArchived() && $status === self::VERSION_ARCHIVED) ) { $this->contentService->deleteVersion($version); ++$removedVersionsCounter; @@ -152,7 +157,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void ), Output::VERBOSITY_VERBOSE); } } - } catch (\Exception $e) { + } catch (Exception $e) { $output->writeln(sprintf( '%s', $e->getMessage() @@ -176,7 +181,7 @@ protected function getObjectsIds(int $keep, string $status): array ->having('count(c.id) > :keep'); $query->setParameter('keep', $keep); - if ($status === self::VERSION_DRAFT || $status === self::VERSION_ARCHIVED) { + if ($status !== self::VERSION_ALL) { $query->where('v.status = :status'); $query->setParameter('status', $this->getVersionInfoStatus($status)); } @@ -186,7 +191,14 @@ protected function getObjectsIds(int $keep, string $status): array return $stmt->fetchAll(PDO::FETCH_ASSOC); } - private function getVersionInfoStatus(string $status): ?int + /** + * @param string $status + * + * @return int + * + * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException + */ + private function getVersionInfoStatus(string $status): int { if ($status === self::VERSION_ARCHIVED) { return VersionInfo::STATUS_ARCHIVED; @@ -194,5 +206,13 @@ private function getVersionInfoStatus(string $status): ?int if ($status === self::VERSION_DRAFT) { return VersionInfo::STATUS_DRAFT; } + + throw new InvalidArgumentException( + 'status', + sprintf( + "Status %s can't be mapped to VersionInfo status.", + $status + ) + ); } } From ed4127c1911567b19c45f2088781b38a050a489d Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Thu, 13 Sep 2018 15:50:32 +0200 Subject: [PATCH 03/13] fixup! fixup! As an Administrator I want to have a CLI command for database cleanup --- .../Command/RemoveVersionsCommand.php | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php index 13fee013e7d..c6a227e32e0 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php @@ -83,12 +83,12 @@ protected function configure(): void 'status', 's', InputOption::VALUE_OPTIONAL, - sprintf( - "Select which version types should be removed: '%s', '%s', '%s'.", - self::VERSION_DRAFT, - self::VERSION_ARCHIVED, - self::VERSION_ALL - ), + sprintf( + "Select which version types should be removed: '%s', '%s', '%s'.", + self::VERSION_DRAFT, + self::VERSION_ARCHIVED, + self::VERSION_ALL + ), self::VERSION_ALL ) ->addOption( @@ -96,7 +96,7 @@ protected function configure(): void 'k', InputOption::VALUE_OPTIONAL, "Sets number of the most recent versions (both drafts and archived) which won't be removed.", - self::DEFAULT_KEEP + self::DEFAULT_KEEP ) ->addOption( 'user', @@ -109,7 +109,13 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): void { - $keep = (int) $input->getOption('keep'); + if (($keep = (int) $input->getOption('keep')) < 0) { + throw new InvalidArgumentException( + 'status', + 'Keep value can not be negative.' + ); + } + $status = $input->getOption('status'); $contentIds = $this->getObjectsIds($keep, $status); @@ -171,6 +177,14 @@ protected function execute(InputInterface $input, OutputInterface $output): void )); } + /** + * @param int $keep + * @param string $status + * + * @return array + * + * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException + */ protected function getObjectsIds(int $keep, string $status): array { $query = $this->connection->createQueryBuilder() @@ -209,10 +223,10 @@ private function getVersionInfoStatus(string $status): int throw new InvalidArgumentException( 'status', - sprintf( - "Status %s can't be mapped to VersionInfo status.", - $status - ) + sprintf( + "Status %s can't be mapped to VersionInfo status.", + $status + ) ); } } From dbe72d4c1755eb2402d346cb489e3190da5e490a Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Fri, 14 Sep 2018 11:44:50 +0200 Subject: [PATCH 04/13] fixup! fixup! fixup! As an Administrator I want to have a CLI command for database cleanup --- .../Command/RemoveVersionsCommand.php | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php index c6a227e32e0..a17a25def98 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php @@ -9,13 +9,14 @@ namespace eZ\Bundle\EzPublishCoreBundle\Command; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\FetchMode; use Exception; +use eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider; use eZ\Publish\API\Repository\ContentService; use eZ\Publish\API\Repository\PermissionResolver; use eZ\Publish\API\Repository\UserService; use eZ\Publish\API\Repository\Values\Content\VersionInfo; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; -use PDO; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -25,7 +26,6 @@ class RemoveVersionsCommand extends Command { const DEFAULT_REPOSITORY_USER = 'admin'; - const DEFAULT_KEEP = 2; const VERSION_DRAFT = 'draft'; const VERSION_ARCHIVED = 'archived'; @@ -46,6 +46,11 @@ class RemoveVersionsCommand extends Command */ private $permissionResolver; + /** + * @var \eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider + */ + private $repositoryConfigurationProvider; + /** * @var \Doctrine\DBAL\Driver\Connection */ @@ -55,11 +60,13 @@ public function __construct( UserService $userService, ContentService $contentService, PermissionResolver $permissionResolver, + RepositoryConfigurationProvider $repositoryConfigurationProvider, Connection $connection ) { $this->userService = $userService; $this->contentService = $contentService; $this->permissionResolver = $permissionResolver; + $this->repositoryConfigurationProvider = $repositoryConfigurationProvider; $this->connection = $connection; parent::__construct(); @@ -76,6 +83,8 @@ protected function initialize(InputInterface $input, OutputInterface $output): v protected function configure(): void { + $config = $this->repositoryConfigurationProvider->getRepositoryConfig(); + $this ->setName('ezplatform:remove-versions') ->setDescription('Remove unwanted content versions. It keeps published version untouched. By default, it keeps also the last archived/draft version.') @@ -96,7 +105,7 @@ protected function configure(): void 'k', InputOption::VALUE_OPTIONAL, "Sets number of the most recent versions (both drafts and archived) which won't be removed.", - self::DEFAULT_KEEP + $config['options']['default_version_archive_limit'] ) ->addOption( 'user', @@ -148,16 +157,20 @@ protected function execute(InputInterface $input, OutputInterface $output): void $versions = array_slice(array_reverse($versions), $keep); + $removeAll = $status === self::VERSION_ALL; + $removeDrafts = $status === self::VERSION_DRAFT; + $removeArchived = $status === self::VERSION_ARCHIVED; + foreach ($versions as $version) { if ( - (!$version->isPublished() && $status === self::VERSION_ALL) || - ($version->isDraft() && $status === self::VERSION_DRAFT) || - ($version->isArchived() && $status === self::VERSION_ARCHIVED) + ($removeAll && !$version->isPublished()) || + ($removeDrafts && $version->isDraft()) || + ($removeArchived && $version->isArchived()) ) { $this->contentService->deleteVersion($version); ++$removedVersionsCounter; $output->writeln(sprintf( - "Content's (%s) version (%s) has been deleted.", + "Content's (%d) version (%d) has been deleted.", $contentInfo->id, $version->id ), Output::VERBOSITY_VERBOSE); @@ -190,7 +203,7 @@ protected function getObjectsIds(int $keep, string $status): array $query = $this->connection->createQueryBuilder() ->select('c.id, v.status') ->from('ezcontentobject', 'c') - ->leftJoin('c', 'ezcontentobject_version', 'v', 'v.contentobject_id = c.id') + ->join('c', 'ezcontentobject_version', 'v', 'v.contentobject_id = c.id') ->groupBy('c.id', 'v.status') ->having('count(c.id) > :keep'); $query->setParameter('keep', $keep); @@ -202,7 +215,7 @@ protected function getObjectsIds(int $keep, string $status): array $stmt = $query->execute(); - return $stmt->fetchAll(PDO::FETCH_ASSOC); + return $stmt->fetchAll(FetchMode::ASSOCIATIVE); } /** From 4d9c61cf352a1a0702f874ab8819f2dc3cb474d5 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Fri, 14 Sep 2018 13:07:21 +0200 Subject: [PATCH 05/13] Changed command name --- ...sionsCommand.php => CleanupVersionsCommand.php} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename eZ/Bundle/EzPublishCoreBundle/Command/{RemoveVersionsCommand.php => CleanupVersionsCommand.php} (96%) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php similarity index 96% rename from eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php rename to eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index a17a25def98..e1b1f48bda8 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/RemoveVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -23,7 +23,7 @@ use Symfony\Component\Console\Output\Output; use Symfony\Component\Console\Output\OutputInterface; -class RemoveVersionsCommand extends Command +class CleanupVersionsCommand extends Command { const DEFAULT_REPOSITORY_USER = 'admin'; @@ -86,7 +86,7 @@ protected function configure(): void $config = $this->repositoryConfigurationProvider->getRepositoryConfig(); $this - ->setName('ezplatform:remove-versions') + ->setName('ezplatform:content:cleanup-versions') ->setDescription('Remove unwanted content versions. It keeps published version untouched. By default, it keeps also the last archived/draft version.') ->addOption( 'status', @@ -143,15 +143,15 @@ protected function execute(InputInterface $input, OutputInterface $output): void $removedVersionsCounter = 0; - foreach ($contentIds as $contentData) { + foreach ($contentIds as $contentId) { try { - $contentInfo = $this->contentService->loadContentInfo($contentData['id']); + $contentInfo = $this->contentService->loadContentInfo((int) $contentId); $versions = $this->contentService->loadVersions($contentInfo); $versionsCount = count($versions); $output->writeln(sprintf( 'Content %d has %d version(s)', - $contentData['id'], + (int) $contentId, $versionsCount ), Output::VERBOSITY_VERBOSE); @@ -201,7 +201,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void protected function getObjectsIds(int $keep, string $status): array { $query = $this->connection->createQueryBuilder() - ->select('c.id, v.status') + ->select('c.id') ->from('ezcontentobject', 'c') ->join('c', 'ezcontentobject_version', 'v', 'v.contentobject_id = c.id') ->groupBy('c.id', 'v.status') @@ -215,7 +215,7 @@ protected function getObjectsIds(int $keep, string $status): array $stmt = $query->execute(); - return $stmt->fetchAll(FetchMode::ASSOCIATIVE); + return $stmt->fetchAll(FetchMode::COLUMN); } /** From 23e9fb784edba3a97a32e6559b14880ee5f5dbdb Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Mon, 17 Sep 2018 15:32:39 +0200 Subject: [PATCH 06/13] Adapt command for 6.7 --- .../Command/CleanupVersionsCommand.php | 46 ++++++++++--------- .../Resources/config/services.yml | 9 ++-- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index e1b1f48bda8..343035eeb0f 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -4,19 +4,15 @@ * @copyright Copyright (C) eZ Systems AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ -declare(strict_types=1); - namespace eZ\Bundle\EzPublishCoreBundle\Command; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\FetchMode; use Exception; use eZ\Bundle\EzPublishCoreBundle\ApiLoader\RepositoryConfigurationProvider; -use eZ\Publish\API\Repository\ContentService; -use eZ\Publish\API\Repository\PermissionResolver; -use eZ\Publish\API\Repository\UserService; +use eZ\Publish\API\Repository\Repository; use eZ\Publish\API\Repository\Values\Content\VersionInfo; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; +use PDO; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -31,6 +27,11 @@ class CleanupVersionsCommand extends Command const VERSION_ARCHIVED = 'archived'; const VERSION_ALL = 'all'; + /** + * @var \eZ\Publish\API\Repository\Repository + */ + private $repository; + /** * @var \eZ\Publish\API\Repository\UserService */ @@ -57,31 +58,31 @@ class CleanupVersionsCommand extends Command private $connection; public function __construct( - UserService $userService, - ContentService $contentService, - PermissionResolver $permissionResolver, + Repository $repository, RepositoryConfigurationProvider $repositoryConfigurationProvider, Connection $connection ) { - $this->userService = $userService; - $this->contentService = $contentService; - $this->permissionResolver = $permissionResolver; + $this->repository = $repository; $this->repositoryConfigurationProvider = $repositoryConfigurationProvider; $this->connection = $connection; parent::__construct(); } - protected function initialize(InputInterface $input, OutputInterface $output): void + protected function initialize(InputInterface $input, OutputInterface $output) { parent::initialize($input, $output); + $this->userService = $this->repository->getUserService(); + $this->contentService = $this->repository->getContentService(); + $this->permissionResolver = $this->repository->getPermissionResolver(); + $this->permissionResolver->setCurrentUserReference( $this->userService->loadUserByLogin($input->getOption('user')) ); } - protected function configure(): void + protected function configure() { $config = $this->repositoryConfigurationProvider->getRepositoryConfig(); @@ -90,7 +91,7 @@ protected function configure(): void ->setDescription('Remove unwanted content versions. It keeps published version untouched. By default, it keeps also the last archived/draft version.') ->addOption( 'status', - 's', + 't', InputOption::VALUE_OPTIONAL, sprintf( "Select which version types should be removed: '%s', '%s', '%s'.", @@ -116,7 +117,7 @@ protected function configure(): void ); } - protected function execute(InputInterface $input, OutputInterface $output): void + protected function execute(InputInterface $input, OutputInterface $output) { if (($keep = (int) $input->getOption('keep')) < 0) { throw new InvalidArgumentException( @@ -161,11 +162,12 @@ protected function execute(InputInterface $input, OutputInterface $output): void $removeDrafts = $status === self::VERSION_DRAFT; $removeArchived = $status === self::VERSION_ARCHIVED; + /** @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $version */ foreach ($versions as $version) { if ( - ($removeAll && !$version->isPublished()) || - ($removeDrafts && $version->isDraft()) || - ($removeArchived && $version->isArchived()) + ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || + ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || + ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) ) { $this->contentService->deleteVersion($version); ++$removedVersionsCounter; @@ -198,7 +200,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void * * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException */ - protected function getObjectsIds(int $keep, string $status): array + protected function getObjectsIds($keep, $status) { $query = $this->connection->createQueryBuilder() ->select('c.id') @@ -215,7 +217,7 @@ protected function getObjectsIds(int $keep, string $status): array $stmt = $query->execute(); - return $stmt->fetchAll(FetchMode::COLUMN); + return $stmt->fetchAll(PDO::FETCH_COLUMN); } /** @@ -225,7 +227,7 @@ protected function getObjectsIds(int $keep, string $status): array * * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException */ - private function getVersionInfoStatus(string $status): int + private function getVersionInfoStatus($status) { if ($status === self::VERSION_ARCHIVED) { return VersionInfo::STATUS_ARCHIVED; diff --git a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml index 94c1160276b..750bda2dfde 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml +++ b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml @@ -231,8 +231,11 @@ services: tags: - { name: jms_translation.file_visitor, alias: ez_validation_error } - ezplatform.core.command.remove_versions: - class: eZ\Bundle\EzPublishCoreBundle\Command\RemoveVersionsCommand + ezplatform.core.command.cleanup_versions: + class: eZ\Bundle\EzPublishCoreBundle\Command\CleanupVersionsCommand arguments: - - "@ezpublish.api.inner_repository" + - "@ezpublish.signalslot.repository" + - "@ezpublish.api.repository_configuration_provider" - "@ezpublish.persistence.connection" + tags: + - { name: console.command } \ No newline at end of file From f3bfb47a2b516f0a57751bc6d99646ee8af41a24 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Mon, 17 Sep 2018 15:36:02 +0200 Subject: [PATCH 07/13] fixup! Adapt command for 6.7 --- eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml index 750bda2dfde..f2668acc014 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml +++ b/eZ/Bundle/EzPublishCoreBundle/Resources/config/services.yml @@ -238,4 +238,4 @@ services: - "@ezpublish.api.repository_configuration_provider" - "@ezpublish.persistence.connection" tags: - - { name: console.command } \ No newline at end of file + - { name: console.command } From 1726cc021c54133491e89169044ead31f286b9e5 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Tue, 18 Sep 2018 15:50:54 +0200 Subject: [PATCH 08/13] Review improvements --- .../Command/CleanupVersionsCommand.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index 343035eeb0f..ab445598320 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -93,12 +93,12 @@ protected function configure() 'status', 't', InputOption::VALUE_OPTIONAL, - sprintf( - "Select which version types should be removed: '%s', '%s', '%s'.", - self::VERSION_DRAFT, - self::VERSION_ARCHIVED, - self::VERSION_ALL - ), + sprintf( + "Select which version types should be removed: '%s', '%s', '%s'.", + self::VERSION_DRAFT, + self::VERSION_ARCHIVED, + self::VERSION_ALL + ), self::VERSION_ALL ) ->addOption( @@ -156,7 +156,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $versionsCount ), Output::VERBOSITY_VERBOSE); - $versions = array_slice(array_reverse($versions), $keep); + $versions = array_slice($versions, 0, -$keep); $removeAll = $status === self::VERSION_ALL; $removeDrafts = $status === self::VERSION_DRAFT; From a2261270db9a414a3afbc197f03ae93917ee6848 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Mon, 17 Dec 2018 16:32:32 +0100 Subject: [PATCH 09/13] Fixed invalid behavior of version counter --- .../Command/CleanupVersionsCommand.php | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index ab445598320..b0b634ccf49 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -25,6 +25,7 @@ class CleanupVersionsCommand extends Command const VERSION_DRAFT = 'draft'; const VERSION_ARCHIVED = 'archived'; + const VERSION_PUBLISHED = 'published'; const VERSION_ALL = 'all'; /** @@ -156,27 +157,36 @@ protected function execute(InputInterface $input, OutputInterface $output) $versionsCount ), Output::VERBOSITY_VERBOSE); - $versions = array_slice($versions, 0, -$keep); - $removeAll = $status === self::VERSION_ALL; $removeDrafts = $status === self::VERSION_DRAFT; $removeArchived = $status === self::VERSION_ARCHIVED; + $versions = array_slice( + array_filter($versions, function ($version) use ($removeAll, $removeDrafts, $removeArchived) { + if ( + ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || + ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || + ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) + ) { + return $version; + } + }), 0, -$keep); + + $output->writeln(sprintf( + "Found %d content's (%d) version(s) to remove.", + count($versions), + (int) $contentId + ), Output::VERBOSITY_VERBOSE); + /** @var \eZ\Publish\API\Repository\Values\Content\VersionInfo $version */ foreach ($versions as $version) { - if ( - ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || - ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || - ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) - ) { - $this->contentService->deleteVersion($version); - ++$removedVersionsCounter; - $output->writeln(sprintf( - "Content's (%d) version (%d) has been deleted.", - $contentInfo->id, - $version->id - ), Output::VERBOSITY_VERBOSE); - } + $this->contentService->deleteVersion($version); + ++$removedVersionsCounter; + $output->writeln(sprintf( + "Content's (%d) version (%d) has been deleted.", + $contentInfo->id, + $version->id + ), Output::VERBOSITY_VERBOSE); } } catch (Exception $e) { $output->writeln(sprintf( @@ -213,6 +223,9 @@ protected function getObjectsIds($keep, $status) if ($status !== self::VERSION_ALL) { $query->where('v.status = :status'); $query->setParameter('status', $this->getVersionInfoStatus($status)); + } else { + $query->andWhere('v.status != :status'); + $query->setParameter('status', $this->getVersionInfoStatus(self::VERSION_PUBLISHED)); } $stmt = $query->execute(); @@ -235,6 +248,9 @@ private function getVersionInfoStatus($status) if ($status === self::VERSION_DRAFT) { return VersionInfo::STATUS_DRAFT; } + if ($status === self::VERSION_PUBLISHED) { + return VersionInfo::STATUS_PUBLISHED; + } throw new InvalidArgumentException( 'status', From d75927b1613024dcddbee08cfa27643f2ed06cf1 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Tue, 18 Dec 2018 10:25:10 +0100 Subject: [PATCH 10/13] Improved mapping of version status --- .../Command/CleanupVersionsCommand.php | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index b0b634ccf49..7d856ab50f2 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -28,6 +28,12 @@ class CleanupVersionsCommand extends Command const VERSION_PUBLISHED = 'published'; const VERSION_ALL = 'all'; + const VERSION_STATUS = [ + self::VERSION_DRAFT => VersionInfo::STATUS_DRAFT, + self::VERSION_ARCHIVED => VersionInfo::STATUS_ARCHIVED, + self::VERSION_PUBLISHED => VersionInfo::STATUS_PUBLISHED + ]; + /** * @var \eZ\Publish\API\Repository\Repository */ @@ -133,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $contentIdsCount = count($contentIds); if ($contentIdsCount === 0) { - $output->writeln('There is no Contents matching given criteria.'); + $output->writeln('There is no Content matching given criteria.'); return; } @@ -145,6 +151,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $removedVersionsCounter = 0; + $removeAll = $status === self::VERSION_ALL; + $removeDrafts = $status === self::VERSION_DRAFT; + $removeArchived = $status === self::VERSION_ARCHIVED; + foreach ($contentIds as $contentId) { try { $contentInfo = $this->contentService->loadContentInfo((int) $contentId); @@ -157,16 +167,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $versionsCount ), Output::VERBOSITY_VERBOSE); - $removeAll = $status === self::VERSION_ALL; - $removeDrafts = $status === self::VERSION_DRAFT; - $removeArchived = $status === self::VERSION_ARCHIVED; - $versions = array_slice( array_filter($versions, function ($version) use ($removeAll, $removeDrafts, $removeArchived) { if ( - ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || - ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || - ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) + ($removeAll && $version->status !== self::VERSION_STATUS[self::VERSION_PUBLISHED]) || + ($removeDrafts && $version->status === self::VERSION_STATUS[self::VERSION_DRAFT]) || + ($removeArchived && $version->status === self::VERSION_STATUS[self::VERSION_ARCHIVED]) ) { return $version; } @@ -222,10 +228,10 @@ protected function getObjectsIds($keep, $status) if ($status !== self::VERSION_ALL) { $query->where('v.status = :status'); - $query->setParameter('status', $this->getVersionInfoStatus($status)); + $query->setParameter('status', $this->mapStatusToVersionInfoStatus($status)); } else { $query->andWhere('v.status != :status'); - $query->setParameter('status', $this->getVersionInfoStatus(self::VERSION_PUBLISHED)); + $query->setParameter('status', $this->mapStatusToVersionInfoStatus(self::VERSION_PUBLISHED)); } $stmt = $query->execute(); @@ -240,16 +246,10 @@ protected function getObjectsIds($keep, $status) * * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException */ - private function getVersionInfoStatus($status) + private function mapStatusToVersionInfoStatus($status) { - if ($status === self::VERSION_ARCHIVED) { - return VersionInfo::STATUS_ARCHIVED; - } - if ($status === self::VERSION_DRAFT) { - return VersionInfo::STATUS_DRAFT; - } - if ($status === self::VERSION_PUBLISHED) { - return VersionInfo::STATUS_PUBLISHED; + if (array_key_exists($status, self::VERSION_STATUS)) { + return self::VERSION_STATUS[$status]; } throw new InvalidArgumentException( From 9de4eee924ec5957d51daf9829e9efe2bc80f203 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Tue, 18 Dec 2018 10:40:47 +0100 Subject: [PATCH 11/13] fixup! Improved mapping of version status --- .../EzPublishCoreBundle/Command/CleanupVersionsCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index 7d856ab50f2..8eccd51c7fe 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -31,7 +31,7 @@ class CleanupVersionsCommand extends Command const VERSION_STATUS = [ self::VERSION_DRAFT => VersionInfo::STATUS_DRAFT, self::VERSION_ARCHIVED => VersionInfo::STATUS_ARCHIVED, - self::VERSION_PUBLISHED => VersionInfo::STATUS_PUBLISHED + self::VERSION_PUBLISHED => VersionInfo::STATUS_PUBLISHED, ]; /** From 3eab4993291d07cac4b574e70574b5ba79e5bcc9 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Tue, 18 Dec 2018 12:49:54 +0100 Subject: [PATCH 12/13] fixup! fixup! Improved mapping of version status --- .../EzPublishCoreBundle/Command/CleanupVersionsCommand.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index 8eccd51c7fe..ca4c95e92a2 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -170,9 +170,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $versions = array_slice( array_filter($versions, function ($version) use ($removeAll, $removeDrafts, $removeArchived) { if ( - ($removeAll && $version->status !== self::VERSION_STATUS[self::VERSION_PUBLISHED]) || - ($removeDrafts && $version->status === self::VERSION_STATUS[self::VERSION_DRAFT]) || - ($removeArchived && $version->status === self::VERSION_STATUS[self::VERSION_ARCHIVED]) + ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || + ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || + ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) ) { return $version; } From 1ada6b8ba10e8b6044a03ab773f946b1548ba433 Mon Sep 17 00:00:00 2001 From: Kamil Madejski Date: Wed, 19 Dec 2018 15:46:33 +0100 Subject: [PATCH 13/13] Covered edge-case with keep = 0 --- .../Command/CleanupVersionsCommand.php | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php index ca4c95e92a2..a9b4ddb1c03 100644 --- a/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php +++ b/eZ/Bundle/EzPublishCoreBundle/Command/CleanupVersionsCommand.php @@ -167,16 +167,19 @@ protected function execute(InputInterface $input, OutputInterface $output) $versionsCount ), Output::VERBOSITY_VERBOSE); - $versions = array_slice( - array_filter($versions, function ($version) use ($removeAll, $removeDrafts, $removeArchived) { - if ( - ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || - ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || - ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) - ) { - return $version; - } - }), 0, -$keep); + $versions = array_filter($versions, function ($version) use ($removeAll, $removeDrafts, $removeArchived) { + if ( + ($removeAll && $version->status !== VersionInfo::STATUS_PUBLISHED) || + ($removeDrafts && $version->status === VersionInfo::STATUS_DRAFT) || + ($removeArchived && $version->status === VersionInfo::STATUS_ARCHIVED) + ) { + return $version; + } + }); + + if ($keep > 0) { + $versions = array_slice($versions, 0, -$keep); + } $output->writeln(sprintf( "Found %d content's (%d) version(s) to remove.",