Completed
Push — 6.12 ( 1cff2f )
by Łukasz
64:51
created

RemoveContentTranslationCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the eZ Publish Kernel package.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Bundle\EzPublishCoreBundle\Command;
10
11
use eZ\Publish\API\Repository\Repository;
12
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
13
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Input\InputArgument;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Question\ChoiceQuestion;
20
use Symfony\Component\Console\Question\ConfirmationQuestion;
21
use Exception;
22
23
/**
24
 * Console Command which removes a given Translation from all the Versions of a given Content Object.
25
 */
26
class RemoveContentTranslationCommand extends Command
27
{
28
    /**
29
     * @var \eZ\Publish\API\Repository\Repository
30
     */
31
    private $repository;
32
33
    /**
34
     * @var \eZ\Publish\API\Repository\ContentService
35
     */
36
    private $contentService;
37
38
    /**
39
     * @var \Symfony\Component\Console\Input\InputInterface
40
     */
41
    private $input;
42
43
    /**
44
     * @var \Symfony\Component\Console\Output\OutputInterface
45
     */
46
    private $output;
47
48
    /**
49
     * @var \Symfony\Component\Console\Helper\QuestionHelper
50
     */
51
    private $questionHelper;
52
53
    public function __construct(Repository $repository)
54
    {
55
        parent::__construct(null);
56
        $this->repository = $repository;
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function configure()
63
    {
64
        $this
65
            ->setName('ezplatform:remove-content-translation')
66
            ->addArgument('content-id', InputArgument::REQUIRED, 'Content Object Id')
67
            ->addArgument(
68
                'language-code',
69
                InputArgument::REQUIRED,
70
                'Language code of the Translation to be removed'
71
            )
72
            ->addOption(
73
                'user',
74
                'u',
75
                InputOption::VALUE_OPTIONAL,
76
                'eZ Platform username (with Role containing at least Content policies: read, versionread, edit, remove, versionremove)',
77
                'admin'
78
            )
79
            ->setDescription('Remove Translation from all the Versions of a Content Object');
80
    }
81
82
    protected function initialize(InputInterface $input, OutputInterface $output)
83
    {
84
        parent::initialize($input, $output);
85
        $this->input = $input;
86
        $this->output = $output;
87
        $this->questionHelper = $this->getHelper('question');
88
        $this->contentService = $this->repository->getContentService();
89
90
        $this->repository->getPermissionResolver()->setCurrentUserReference(
91
            $this->repository->getUserService()->loadUserByLogin($input->getOption('user'))
92
        );
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98
    protected function execute(InputInterface $input, OutputInterface $output)
99
    {
100
        $contentId = (int) ($input->getArgument('content-id'));
101
        $languageCode = $input->getArgument('language-code');
102
103
        if ($contentId === 0) {
104
            throw new InvalidArgumentException(
105
                'content-id',
106
                'Content Object Id has to be an integer'
107
            );
108
        }
109
110
        $this->output->writeln(
111
            '<comment>**NOTE**: Make sure to run this command using the same SYMFONY_ENV setting as your eZ Platform installation does</comment>'
112
        );
113
114
        $contentInfo = $this->contentService->loadContentInfo($contentId);
115
116
        $this->repository->beginTransaction();
117
        try {
118
            $allLanguages = $this->removeAffectedSingularLanguageVersions(
119
                $contentInfo,
120
                $languageCode
121
            );
122
            if ($contentInfo->mainLanguageCode === $languageCode) {
123
                $contentInfo = $this->promptUserForMainLanguageChange(
124
                    $contentInfo,
125
                    $languageCode,
126
                    $allLanguages
127
                );
128
            }
129
130
            // Confirm operation
131
            $contentName = "#{$contentInfo->id} ($contentInfo->name)";
132
            $question = new ConfirmationQuestion(
133
                "Are you sure you want to remove {$languageCode} Translation from the Content {$contentName}? This operation is permanent. [y/N] ",
134
                false
135
            );
136
            if (!$this->questionHelper->ask($this->input, $this->output, $question)) {
137
                // Rollback any cleanup change (see above)
138
                $this->repository->rollback();
139
                $this->output->writeln('Reverting and aborting.');
140
141
                return;
142
            }
143
144
            // Remove Translation
145
            $output->writeln(
146
                "<info>Removing {$languageCode} Translation of the Content {$contentName}</info>"
147
            );
148
            $this->contentService->removeTranslation($contentInfo, $languageCode);
149
150
            $output->writeln('<info>Translation removed</info>');
151
152
            $this->repository->commit();
153
        } catch (Exception $e) {
154
            $this->repository->rollback();
155
            throw $e;
156
        }
157
    }
158
159
    /**
160
     * Cleanup Versions before removing Translation and collect existing Translations languages.
161
     *
162
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
163
     * @param string $languageCode
164
     *
165
     * @return string[] unique Language codes across all Versions of the Content.
166
     */
167
    private function removeAffectedSingularLanguageVersions(ContentInfo $contentInfo, $languageCode)
168
    {
169
        $languages = [];
170
        foreach ($this->contentService->loadVersions($contentInfo) as $versionInfo) {
171
            // if this is the only one Translation, just delete entire Version
172
            if (count($versionInfo->languageCodes) === 1 && $versionInfo->languageCodes[0] === $languageCode) {
173
                // Note: won't work on published Versions and last remaining Version
174
                $this->contentService->deleteVersion($versionInfo);
175
                continue;
176
            }
177
178
            foreach ($versionInfo->languageCodes as $lang) {
179
                if ($lang === $languageCode || in_array($lang, $languages)) {
180
                    continue;
181
                }
182
                $languages[] = $lang;
183
            }
184
        }
185
186
        return $languages;
187
    }
188
189
    /**
190
     * Interact with user to update main Language of a Content Object.
191
     *
192
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
193
     * @param string $languageCode language code of the Translation to be removed
194
     * @param string[] $allLanguages all languages Content Object Versions have, w/o $languageCode
195
     *
196
     * @return \eZ\Publish\API\Repository\Values\Content\ContentInfo
197
     */
198
    private function promptUserForMainLanguageChange(
199
        ContentInfo $contentInfo,
200
        $languageCode,
201
        array $allLanguages
202
    ) {
203
        $contentName = "#{$contentInfo->id} ($contentInfo->name)";
204
        $this->output->writeln(
205
            "<comment>The specified language '{$languageCode}' is the main language of the Content {$contentName}. It needs to be changed before removal.</comment>"
206
        );
207
208
        $question = new ChoiceQuestion(
209
            "Set the main language of the Content {$contentName} to:",
210
            $allLanguages
211
        );
212
213
        $newMainLanguageCode = $this->questionHelper->ask($this->input, $this->output, $question);
214
        $this->output->writeln(
215
            "<info>Updating Main Language of the Content {$contentName} to {$newMainLanguageCode}</info>"
216
        );
217
218
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
219
        $contentMetadataUpdateStruct->mainLanguageCode = $newMainLanguageCode;
220
221
        return $this->contentService->updateContentMetadata(
222
            $contentInfo,
223
            $contentMetadataUpdateStruct
224
        )->contentInfo;
225
    }
226
}
227