Completed
Push — master ( 721b68...94d8f9 )
by Łukasz
30:24 queued 09:37
created

CopySubtreeCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 5
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Bundle\EzPublishCoreBundle\Command;
8
9
use eZ\Publish\API\Repository\ContentTypeService;
10
use eZ\Publish\API\Repository\LocationService;
11
use eZ\Publish\API\Repository\PermissionResolver;
12
use eZ\Publish\API\Repository\SearchService;
13
use eZ\Publish\API\Repository\UserService;
14
use eZ\Publish\API\Repository\Values\Content\Location;
15
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
18
use Symfony\Component\Console\Command\Command;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Question\ConfirmationQuestion;
24
25
/**
26
 * Console command for deep copying subtree from one location to another.
27
 */
28
class CopySubtreeCommand extends Command
29
{
30
    /**
31
     * @var \eZ\Publish\API\Repository\LocationService
32
     */
33
    private $locationService;
34
35
    /**
36
     * @var \eZ\Publish\API\Repository\PermissionResolver
37
     */
38
    private $permissionResolver;
39
40
    /**
41
     * @var \eZ\Publish\API\Repository\UserService
42
     */
43
    private $userService;
44
45
    /**
46
     * @var \eZ\Publish\API\Repository\ContentTypeService
47
     */
48
    private $contentTypeService;
49
50
    /**
51
     * @var \eZ\Publish\API\Repository\SearchService
52
     */
53
    private $searchService;
54
55
    /**
56
     * @param \eZ\Publish\API\Repository\LocationService $locationService
57
     * @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
58
     * @param \eZ\Publish\API\Repository\UserService $userService
59
     * @param \eZ\Publish\API\Repository\ContentTypeService $contentTypeService
60
     * @param \eZ\Publish\API\Repository\SearchService $searchService
61
     */
62
    public function __construct(
63
        LocationService $locationService,
64
        PermissionResolver $permissionResolver,
65
        UserService $userService,
66
        ContentTypeService $contentTypeService,
67
        SearchService $searchService
68
    ) {
69
        parent::__construct();
70
        $this->locationService = $locationService;
71
        $this->permissionResolver = $permissionResolver;
72
        $this->userService = $userService;
73
        $this->contentTypeService = $contentTypeService;
74
        $this->searchService = $searchService;
75
    }
76
77
    protected function configure()
78
    {
79
        $this
80
            ->setName('ezplatform:copy-subtree')
81
            ->addArgument(
82
                'source-location-id',
83
                InputArgument::REQUIRED,
84
                'Id of subtree root location'
85
            )
86
            ->addArgument(
87
                'target-location-id',
88
                InputArgument::REQUIRED,
89
                'Id of target location'
90
            )
91
            ->addOption(
92
                'user',
93
                'u',
94
                InputOption::VALUE_OPTIONAL,
95
                'eZ Platform username (with Role containing at least Content policies: create, read)',
96
                'admin'
97
            )
98
            ->setDescription('Copy subtree from one location to another');
99
    }
100
101
    /**
102
     * @param \Symfony\Component\Console\Input\InputInterface $input
103
     * @param \Symfony\Component\Console\Output\OutputInterface $output
104
     *
105
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
106
     */
107
    protected function initialize(InputInterface $input, OutputInterface $output)
108
    {
109
        parent::initialize($input, $output);
110
        $this->permissionResolver->setCurrentUserReference(
111
            $this->userService->loadUserByLogin($input->getOption('user'))
112
        );
113
    }
114
115
    /**
116
     * @param \Symfony\Component\Console\Input\InputInterface $input
117
     * @param \Symfony\Component\Console\Output\OutputInterface $output
118
     *
119
     * @return int|null
120
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
121
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
122
     * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentException
123
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
124
     */
125
    protected function execute(InputInterface $input, OutputInterface $output)
126
    {
127
        $sourceLocationId = $input->getArgument('source-location-id');
128
        $targetLocationId = $input->getArgument('target-location-id');
129
130
        $sourceLocation = $this->locationService->loadLocation($sourceLocationId);
131
        $targetLocation = $this->locationService->loadLocation($targetLocationId);
132
133
        if (stripos($targetLocation->pathString, $sourceLocation->pathString) !== false) {
134
            throw new InvalidArgumentException(
135
                'target-location-id',
136
                'Target parent location is a sub location of the source subtree'
137
            );
138
        }
139
140
        $targetContentType = $this->contentTypeService->loadContentType(
141
            $targetLocation->getContentInfo()->contentTypeId
142
        );
143
144
        if (!$targetContentType->isContainer) {
145
            throw new InvalidArgumentException(
146
                'target-location-id',
147
                'Cannot copy location to a parent that is not a container'
148
            );
149
        }
150
        $questionHelper = $this->getHelper('question');
151
        $question = new ConfirmationQuestion(
152
            sprintf(
153
                'Are you sure you want to copy `%s` subtree (no. of children: %d) into `%s`? This make take a while for big number of nested children [Y/n]? ',
154
                $sourceLocation->contentInfo->name,
155
                $this->getAllChildrenCount($sourceLocation),
156
                $targetLocation->contentInfo->name
157
            )
158
        );
159
160
        if (!$input->getOption('no-interaction') && !$questionHelper->ask($input, $output, $question)) {
161
            return 0;
162
        }
163
164
        $this->locationService->copySubtree(
165
            $sourceLocation,
166
            $targetLocation
167
        );
168
169
        $output->writeln(
170
            '<info>Finished</info>'
171
        );
172
173
        return 0;
174
    }
175
176
    /**
177
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
178
     *
179
     * @return int
180
     *
181
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
182
     */
183
    protected function getAllChildrenCount(Location $location): int
184
    {
185
        $query = new LocationQuery([
186
            'filter' => new Criterion\Subtree($location->pathString),
187
        ]);
188
189
        $searchResults = $this->searchService->findLocations($query);
190
191
        return $searchResults->totalCount;
192
    }
193
}
194