Completed
Push — ezp-29724 ( 1025e5...495423 )
by
unknown
30:13 queued 07:05
created

SectionService::assignSectionToSubtree()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
c 0
b 0
f 0
cc 5
nc 8
nop 2
rs 8.7143

3 Methods

Rating   Name   Duplication   Size   Complexity  
A SectionService::newSectionCreateStruct() 0 4 1
A SectionService::newSectionUpdateStruct() 0 4 1
A SectionService::buildDomainSectionObject() 0 10 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * File containing the eZ\Publish\Core\Repository\SectionService class.
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\Publish\Core\Repository;
10
11
use eZ\Publish\API\Repository\Values\Content\SectionCreateStruct;
12
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
13
use eZ\Publish\API\Repository\Values\Content\Section;
14
use eZ\Publish\API\Repository\Values\Content\SectionUpdateStruct;
15
use eZ\Publish\API\Repository\SectionService as SectionServiceInterface;
16
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
17
use eZ\Publish\SPI\Persistence\Content\Section\Handler;
18
use eZ\Publish\SPI\Persistence\Content\Section as SPISection;
19
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue;
20
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
21
use eZ\Publish\Core\Base\Exceptions\BadStateException;
22
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
23
use eZ\Publish\API\Repository\Exceptions\NotFoundException as APINotFoundException;
24
use Exception;
25
26
/**
27
 * Section service, used for section operations.
28
 */
29
class SectionService implements SectionServiceInterface
30
{
31
    /**
32
     * @var \eZ\Publish\API\Repository\Repository
33
     */
34
    protected $repository;
35
36
    /**
37
     * @var \eZ\Publish\API\Repository\PermissionResolver
38
     */
39
    protected $permissionResolver;
40
41
    /**
42
     * @var \eZ\Publish\SPI\Persistence\Content\Section\Handler
43
     */
44
    protected $sectionHandler;
45
46
    /**
47
     * @var array
48
     */
49
    protected $settings;
50
51
    /**
52
     * Setups service with reference to repository object that created it & corresponding handler.
53
     *
54
     * @param \eZ\Publish\API\Repository\Repository $repository
55
     * @param \eZ\Publish\SPI\Persistence\Content\Section\Handler $sectionHandler
56
     * @param array $settings
57
     */
58
    public function __construct(RepositoryInterface $repository, Handler $sectionHandler, array $settings = array())
59
    {
60
        $this->repository = $repository;
61
        $this->permissionResolver = $repository->getPermissionResolver();
62
        $this->sectionHandler = $sectionHandler;
63
        // Union makes sure default settings are ignored if provided in argument
64
        $this->settings = $settings + array(
65
            //'defaultSetting' => array(),
66
        );
67
    }
68
69
    /**
70
     * Creates a new Section in the content repository.
71
     *
72
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to create a section
73
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the new identifier in $sectionCreateStruct already exists
74
     *
75
     * @param \eZ\Publish\API\Repository\Values\Content\SectionCreateStruct $sectionCreateStruct
76
     *
77
     * @return \eZ\Publish\API\Repository\Values\Content\Section The newly created section
78
     */
79
    public function createSection(SectionCreateStruct $sectionCreateStruct)
80
    {
81 View Code Duplication
        if (!is_string($sectionCreateStruct->name) || empty($sectionCreateStruct->name)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
            throw new InvalidArgumentValue('name', $sectionCreateStruct->name, 'SectionCreateStruct');
83
        }
84
85 View Code Duplication
        if (!is_string($sectionCreateStruct->identifier) || empty($sectionCreateStruct->identifier)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
            throw new InvalidArgumentValue('identifier', $sectionCreateStruct->identifier, 'SectionCreateStruct');
87
        }
88
89
        if (!$this->permissionResolver->canUser('section', 'edit', $sectionCreateStruct)) {
90
            throw new UnauthorizedException('section', 'edit');
91
        }
92
93
        try {
94
            $existingSection = $this->loadSectionByIdentifier($sectionCreateStruct->identifier);
95
            if ($existingSection !== null) {
96
                throw new InvalidArgumentException('sectionCreateStruct', 'section with specified identifier already exists');
97
            }
98
        } catch (APINotFoundException $e) {
99
            // Do nothing
100
        }
101
102
        $this->repository->beginTransaction();
103
        try {
104
            $spiSection = $this->sectionHandler->create(
105
                $sectionCreateStruct->name,
106
                $sectionCreateStruct->identifier
107
            );
108
            $this->repository->commit();
109
        } catch (Exception $e) {
110
            $this->repository->rollback();
111
            throw $e;
112
        }
113
114
        return $this->buildDomainSectionObject($spiSection);
115
    }
116
117
    /**
118
     * Updates the given section in the content repository.
119
     *
120
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to create a section
121
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the new identifier already exists (if set in the update struct)
122
     *
123
     * @param \eZ\Publish\API\Repository\Values\Content\Section $section
124
     * @param \eZ\Publish\API\Repository\Values\Content\SectionUpdateStruct $sectionUpdateStruct
125
     *
126
     * @return \eZ\Publish\API\Repository\Values\Content\Section
127
     */
128
    public function updateSection(Section $section, SectionUpdateStruct $sectionUpdateStruct)
129
    {
130 View Code Duplication
        if ($sectionUpdateStruct->name !== null && !is_string($sectionUpdateStruct->name)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
            throw new InvalidArgumentValue('name', $section->name, 'Section');
132
        }
133
134 View Code Duplication
        if ($sectionUpdateStruct->identifier !== null && !is_string($sectionUpdateStruct->identifier)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
            throw new InvalidArgumentValue('identifier', $section->identifier, 'Section');
136
        }
137
138
        if (!$this->permissionResolver->canUser('section', 'edit', $section)) {
139
            throw new UnauthorizedException('section', 'edit');
140
        }
141
142
        if ($sectionUpdateStruct->identifier !== null) {
143
            try {
144
                $existingSection = $this->loadSectionByIdentifier($sectionUpdateStruct->identifier);
145
146
                // Allowing identifier update only for the same section
147
                if ($existingSection->id != $section->id) {
148
                    throw new InvalidArgumentException('sectionUpdateStruct', 'section with specified identifier already exists');
149
                }
150
            } catch (APINotFoundException $e) {
151
                // Do nothing
152
            }
153
        }
154
155
        $loadedSection = $this->loadSection($section->id);
156
157
        $this->repository->beginTransaction();
158
        try {
159
            $spiSection = $this->sectionHandler->update(
160
                $loadedSection->id,
161
                $sectionUpdateStruct->name ?: $loadedSection->name,
162
                $sectionUpdateStruct->identifier ?: $loadedSection->identifier
163
            );
164
            $this->repository->commit();
165
        } catch (Exception $e) {
166
            $this->repository->rollback();
167
            throw $e;
168
        }
169
170
        return $this->buildDomainSectionObject($spiSection);
171
    }
172
173
    /**
174
     * Loads a Section from its id ($sectionId).
175
     *
176
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if section could not be found
177
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to read a section
178
     *
179
     * @param mixed $sectionId
180
     *
181
     * @return \eZ\Publish\API\Repository\Values\Content\Section
182
     */
183
    public function loadSection($sectionId)
184
    {
185
        $section = $this->buildDomainSectionObject(
186
            $this->sectionHandler->load($sectionId)
187
        );
188
189
        if (!$this->permissionResolver->canUser('section', 'view', $section)) {
190
            throw new UnauthorizedException('section', 'view');
191
        }
192
193
        return $section;
194
    }
195
196
    /**
197
     * Loads all sections.
198
     *
199
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to read a section
200
     *
201
     * @return \eZ\Publish\API\Repository\Values\Content\Section[]
202
     */
203
    public function loadSections()
204
    {
205
        $sections = [];
206
        foreach ($this->sectionHandler->loadAll() as $spiSection) {
207
            $sections[] = $section = $this->buildDomainSectionObject($spiSection);
208
209
            // @todo change API to just filter instead of throwing here
210
            if (!$this->permissionResolver->canUser('section', 'view', $section)) {
211
                throw new UnauthorizedException('section', 'view');
212
            }
213
        }
214
215
        return $sections;
216
    }
217
218
    /**
219
     * Loads a Section from its identifier ($sectionIdentifier).
220
     *
221
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if section could not be found
222
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to read a section
223
     *
224
     * @param string $sectionIdentifier
225
     *
226
     * @return \eZ\Publish\API\Repository\Values\Content\Section
227
     */
228
    public function loadSectionByIdentifier($sectionIdentifier)
229
    {
230
        if (!is_string($sectionIdentifier) || empty($sectionIdentifier)) {
231
            throw new InvalidArgumentValue('sectionIdentifier', $sectionIdentifier);
232
        }
233
234
        $section = $this->buildDomainSectionObject(
235
            $this->sectionHandler->loadByIdentifier($sectionIdentifier)
236
        );
237
238
        if (!$this->permissionResolver->canUser('section', 'view', $section)) {
239
            throw new UnauthorizedException('section', 'view');
240
        }
241
242
        return $section;
243
    }
244
245
    /**
246
     * Counts the contents which $section is assigned to.
247
     *
248
     * @param \eZ\Publish\API\Repository\Values\Content\Section $section
249
     *
250
     * @return int
251
     *
252
     * @deprecated since 6.0
253
     */
254
    public function countAssignedContents(Section $section)
255
    {
256
        return $this->sectionHandler->assignmentsCount($section->id);
257
    }
258
259
    /**
260
     * Returns true if the given section is assigned to contents, or used in role policies, or in role assignments.
261
     *
262
     * This does not check user permissions.
263
     *
264
     * @since 6.0
265
     *
266
     * @param \eZ\Publish\API\Repository\Values\Content\Section $section
267
     *
268
     * @return bool
269
     */
270
    public function isSectionUsed(Section $section)
271
    {
272
        return $this->sectionHandler->assignmentsCount($section->id) > 0 ||
273
               $this->sectionHandler->policiesCount($section->id) > 0 ||
274
               $this->sectionHandler->countRoleAssignmentsUsingSection($section->id) > 0;
275
    }
276
277
    /**
278
     * Assigns the content to the given section
279
     * this method overrides the current assigned section.
280
     *
281
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If user does not have access to view provided object
282
     *
283
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
284
     * @param \eZ\Publish\API\Repository\Values\Content\Section $section
285
     */
286
    public function assignSection(ContentInfo $contentInfo, Section $section)
287
    {
288
        $loadedContentInfo = $this->repository->getContentService()->loadContentInfo($contentInfo->id);
289
        $loadedSection = $this->loadSection($section->id);
290
291
        if (!$this->permissionResolver->canUser('section', 'assign', $loadedContentInfo, [$loadedSection])) {
292
            throw new UnauthorizedException(
293
                'section',
294
                'assign',
295
                array(
296
                    'name' => $loadedSection->name,
297
                    'content-name' => $loadedContentInfo->name,
298
                )
299
            );
300
        }
301
302
        $this->repository->beginTransaction();
303
        try {
304
            $this->sectionHandler->assign(
305
                $loadedSection->id,
306
                $loadedContentInfo->id
307
            );
308
            $this->repository->commit();
309
        } catch (Exception $e) {
310
            $this->repository->rollback();
311
            throw $e;
312
        }
313
    }
314
315
    /**
316
     * Deletes $section from content repository.
317
     *
318
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException If the specified section is not found
319
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete a section
320
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If section can not be deleted
321
     *         because it is still assigned to some contents,
322
     *         or because it is still being used in policy limitations.
323
     *
324
     * @param \eZ\Publish\API\Repository\Values\Content\Section $section
325
     */
326
    public function deleteSection(Section $section)
327
    {
328
        $loadedSection = $this->loadSection($section->id);
329
330
        if (!$this->permissionResolver->canUser('section', 'edit', $loadedSection)) {
331
            throw new UnauthorizedException('section', 'edit', array('sectionId' => $loadedSection->id));
332
        }
333
334
        if ($this->sectionHandler->assignmentsCount($loadedSection->id) > 0) {
335
            throw new BadStateException('section', 'section is still assigned to content');
336
        }
337
338
        if ($this->sectionHandler->policiesCount($loadedSection->id) > 0) {
339
            throw new BadStateException('section', 'section is still being used in policy limitations');
340
        }
341
342
        $this->repository->beginTransaction();
343
        try {
344
            $this->sectionHandler->delete($loadedSection->id);
345
            $this->repository->commit();
346
        } catch (Exception $e) {
347
            $this->repository->rollback();
348
            throw $e;
349
        }
350
    }
351
352
    /**
353
     * Instantiates a new SectionCreateStruct.
354
     *
355
     * @return \eZ\Publish\API\Repository\Values\Content\SectionCreateStruct
356
     */
357
    public function newSectionCreateStruct()
358
    {
359
        return new SectionCreateStruct();
360
    }
361
362
    /**
363
     * Instantiates a new SectionUpdateStruct.
364
     *
365
     * @return \eZ\Publish\API\Repository\Values\Content\SectionUpdateStruct
366
     */
367
    public function newSectionUpdateStruct()
368
    {
369
        return new SectionUpdateStruct();
370
    }
371
372
    /**
373
     * Builds API Section object from provided SPI Section object.
374
     *
375
     * @param \eZ\Publish\SPI\Persistence\Content\Section $spiSection
376
     *
377
     * @return \eZ\Publish\API\Repository\Values\Content\Section
378
     */
379
    protected function buildDomainSectionObject(SPISection $spiSection)
380
    {
381
        return new Section(
382
            array(
383
                'id' => $spiSection->id,
384
                'identifier' => $spiSection->identifier,
385
                'name' => $spiSection->name,
386
            )
387
        );
388
    }
389
}
390