Completed
Push — test-EZP-26707-issearchable-fu... ( 965a07...6812c2 )
by
unknown
33:45 queued 07:39
created

Repository::canUser()   D

Complexity

Conditions 14
Paths 26

Size

Total Lines 85
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 33
nc 26
nop 4
dl 0
loc 85
rs 4.9516
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * Repository 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
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\Core\Repository;
12
13
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
14
use eZ\Publish\API\Repository\Values\ValueObject;
15
use eZ\Publish\API\Repository\Values\User\User;
16
use eZ\Publish\API\Repository\Values\User\UserReference as APIUserReference;
17
use eZ\Publish\API\Repository\Values\User\Limitation;
18
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
19
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue;
20
use eZ\Publish\Core\Repository\Values\User\UserReference;
21
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
22
use eZ\Publish\SPI\Search\Handler as SearchHandler;
23
use eZ\Publish\SPI\Limitation\Type as LimitationType;
24
use Exception;
25
use RuntimeException;
26
27
/**
28
 * Repository class.
29
 */
30
class Repository implements RepositoryInterface
31
{
32
    /**
33
     * Repository Handler object.
34
     *
35
     * @var \eZ\Publish\SPI\Persistence\Handler
36
     */
37
    protected $persistenceHandler;
38
39
    /**
40
     * Instance of main Search Handler.
41
     *
42
     * @var \eZ\Publish\SPI\Search\Handler
43
     */
44
    protected $searchHandler;
45
46
    /**
47
     * Currently logged in user object if already loaded.
48
     *
49
     * @var \eZ\Publish\API\Repository\Values\User\User|null
50
     */
51
    protected $currentUser;
52
53
    /**
54
     * Currently logged in user reference for permission purposes.
55
     *
56
     * @var \eZ\Publish\API\Repository\Values\User\UserReference
57
     */
58
    protected $currentUserRef;
59
60
    /**
61
     * Counter for the current sudo nesting level {@see sudo()}.
62
     *
63
     * @var int
64
     */
65
    private $sudoNestingLevel = 0;
66
67
    /**
68
     * Instance of content service.
69
     *
70
     * @var \eZ\Publish\API\Repository\ContentService
71
     */
72
    protected $contentService;
73
74
    /**
75
     * Instance of section service.
76
     *
77
     * @var \eZ\Publish\API\Repository\SectionService
78
     */
79
    protected $sectionService;
80
81
    /**
82
     * Instance of role service.
83
     *
84
     * @var \eZ\Publish\API\Repository\RoleService
85
     */
86
    protected $roleService;
87
88
    /**
89
     * Instance of search service.
90
     *
91
     * @var \eZ\Publish\API\Repository\SearchService
92
     */
93
    protected $searchService;
94
95
    /**
96
     * Instance of user service.
97
     *
98
     * @var \eZ\Publish\API\Repository\UserService
99
     */
100
    protected $userService;
101
102
    /**
103
     * Instance of language service.
104
     *
105
     * @var \eZ\Publish\API\Repository\LanguageService
106
     */
107
    protected $languageService;
108
109
    /**
110
     * Instance of location service.
111
     *
112
     * @var \eZ\Publish\API\Repository\LocationService
113
     */
114
    protected $locationService;
115
116
    /**
117
     * Instance of Trash service.
118
     *
119
     * @var \eZ\Publish\API\Repository\TrashService
120
     */
121
    protected $trashService;
122
123
    /**
124
     * Instance of content type service.
125
     *
126
     * @var \eZ\Publish\API\Repository\ContentTypeService
127
     */
128
    protected $contentTypeService;
129
130
    /**
131
     * Instance of object state service.
132
     *
133
     * @var \eZ\Publish\API\Repository\ObjectStateService
134
     */
135
    protected $objectStateService;
136
137
    /**
138
     * Instance of field type service.
139
     *
140
     * @var \eZ\Publish\API\Repository\FieldTypeService
141
     */
142
    protected $fieldTypeService;
143
144
    /**
145
     * Instance of FieldTypeRegistry.
146
     *
147
     * @var \eZ\Publish\Core\Repository\Helper\FieldTypeRegistry
148
     */
149
    private $fieldTypeRegistry;
150
151
    /**
152
     * Instance of name schema resolver service.
153
     *
154
     * @var \eZ\Publish\Core\Repository\Helper\NameSchemaService
155
     */
156
    protected $nameSchemaService;
157
158
    /**
159
     * Instance of relation processor service.
160
     *
161
     * @var \eZ\Publish\Core\Repository\Helper\RelationProcessor
162
     */
163
    protected $relationProcessor;
164
165
    /**
166
     * Instance of URL alias service.
167
     *
168
     * @var \eZ\Publish\Core\Repository\URLAliasService
169
     */
170
    protected $urlAliasService;
171
172
    /**
173
     * Instance of URL wildcard service.
174
     *
175
     * @var \eZ\Publish\Core\Repository\URLWildcardService
176
     */
177
    protected $urlWildcardService;
178
179
    /**
180
     * Service settings, first level key is service name.
181
     *
182
     * @var array
183
     */
184
    protected $serviceSettings;
185
186
    /**
187
     * Instance of role service.
188
     *
189
     * @var \eZ\Publish\Core\Repository\Helper\LimitationService
190
     */
191
    protected $limitationService;
192
193
    /**
194
     * @var \eZ\Publish\Core\Repository\Helper\RoleDomainMapper
195
     */
196
    protected $roleDomainMapper;
197
198
    /**
199
     * Instance of domain mapper.
200
     *
201
     * @var \eZ\Publish\Core\Repository\Helper\DomainMapper
202
     */
203
    protected $domainMapper;
204
205
    /**
206
     * Instance of permissions criterion handler.
207
     *
208
     * @var \eZ\Publish\Core\Repository\PermissionsCriterionHandler
209
     */
210
    protected $permissionsCriterionHandler;
211
212
    /**
213
     * Array of arrays of commit events indexed by the transaction count.
214
     *
215
     * @var array
216
     */
217
    protected $commitEventsQueue = array();
218
219
    /**
220
     * @var int
221
     */
222
    protected $transactionDepth = 0;
223
224
    /**
225
     * @var int
226
     */
227
    private $transactionCount = 0;
228
229
    /**
230
     * Constructor.
231
     *
232
     * Construct repository object with provided storage engine
233
     *
234
     * @param \eZ\Publish\SPI\Persistence\Handler $persistenceHandler
235
     * @param \eZ\Publish\SPI\Search\Handler $searchHandler
236
     * @param array $serviceSettings
237
     * @param \eZ\Publish\API\Repository\Values\User\UserReference|null $user
238
     */
239
    public function __construct(
240
        PersistenceHandler $persistenceHandler,
241
        SearchHandler $searchHandler,
242
        array $serviceSettings = array(),
243
        APIUserReference $user = null
244
    ) {
245
        $this->persistenceHandler = $persistenceHandler;
246
        $this->searchHandler = $searchHandler;
247
        $this->serviceSettings = $serviceSettings + array(
248
            'content' => array(),
249
            'contentType' => array(),
250
            'location' => array(),
251
            'section' => array(),
252
            'role' => array(),
253
            'user' => array(
254
                'anonymousUserID' => 10,
255
            ),
256
            'language' => array(),
257
            'trash' => array(),
258
            'io' => array(),
259
            'objectState' => array(),
260
            'search' => array(),
261
            'fieldType' => array(),
262
            'urlAlias' => array(),
263
            'urlWildcard' => array(),
264
            'nameSchema' => array(),
265
            'languages' => array(),
266
        );
267
268
        if (!empty($this->serviceSettings['languages'])) {
269
            $this->serviceSettings['language']['languages'] = $this->serviceSettings['languages'];
270
        }
271
272
        if ($user instanceof User) {
273
            $this->currentUser = $user;
274
            $this->currentUserRef = new UserReference($user->getUserId());
275
        } elseif ($user instanceof APIUserReference) {
276
            $this->currentUserRef = $user;
277
        } else {
278
            $this->currentUserRef = new UserReference($this->serviceSettings['user']['anonymousUserID']);
279
        }
280
    }
281
282
    /**
283
     * Get current user.
284
     *
285
     * Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}
286
     *
287
     * @return \eZ\Publish\API\Repository\Values\User\User
288
     */
289
    public function getCurrentUser()
290
    {
291
        if ($this->currentUser === null) {
292
            $this->currentUser = $this->getUserService()->loadUser(
293
                $this->currentUserRef->getUserId()
294
            );
295
        }
296
297
        return $this->currentUser;
298
    }
299
300
    /**
301
     * Get current user reference.
302
     *
303
     * @since 5.4.5
304
     * @return \eZ\Publish\API\Repository\Values\User\UserReference
305
     */
306
    public function getCurrentUserReference()
307
    {
308
        return $this->currentUserRef;
309
    }
310
311
    /**
312
     * Sets the current user to the given $user.
313
     *
314
     * @param \eZ\Publish\API\Repository\Values\User\UserReference $user
315
     *
316
     * @throws InvalidArgumentValue If UserReference does not contain a id
317
     */
318
    public function setCurrentUser(APIUserReference $user)
319
    {
320
        $id = $user->getUserId();
321
        if (!$id) {
322
            throw new InvalidArgumentValue('$user->getUserId()', $id);
323
        }
324
325
        if ($user instanceof User) {
326
            $this->currentUser = $user;
327
            $this->currentUserRef = new UserReference($id);
328
        } else {
329
            $this->currentUser = null;
330
            $this->currentUserRef = $user;
331
        }
332
    }
333
334
    /**
335
     * Allows API execution to be performed with full access sand-boxed.
336
     *
337
     * The closure sandbox will do a catch all on exceptions and rethrow after
338
     * re-setting the sudo flag.
339
     *
340
     * Example use:
341
     *     $location = $repository->sudo(
342
     *         function ( Repository $repo ) use ( $locationId )
343
     *         {
344
     *             return $repo->getLocationService()->loadLocation( $locationId )
345
     *         }
346
     *     );
347
     *
348
     *
349
     * @param \Closure $callback
350
     * @param \eZ\Publish\API\Repository\Repository $outerRepository
351
     *
352
     * @throws \RuntimeException Thrown on recursive sudo() use.
353
     * @throws \Exception Re throws exceptions thrown inside $callback
354
     *
355
     * @return mixed
356
     */
357
    public function sudo(\Closure $callback, RepositoryInterface $outerRepository = null)
358
    {
359
        ++$this->sudoNestingLevel;
360
        try {
361
            $returnValue = $callback($outerRepository !== null ? $outerRepository : $this);
362
        } catch (Exception $e) {
363
            --$this->sudoNestingLevel;
364
            throw $e;
365
        }
366
367
        --$this->sudoNestingLevel;
368
369
        return $returnValue;
370
    }
371
372
    /**
373
     * Check if user has access to a given module / function.
374
     *
375
     * Low level function, use canUser instead if you have objects to check against.
376
     *
377
     * @param string $module
378
     * @param string $function
379
     * @param \eZ\Publish\API\Repository\Values\User\UserReference $user
380
     *
381
     * @return bool|array Bool if user has full or no access, array if limitations if not
382
     */
383
    public function hasAccess($module, $function, APIUserReference $user = null)
384
    {
385
        // Full access if sudo nesting level is set by {@see sudo()}
386
        if ($this->sudoNestingLevel > 0) {
387
            return true;
388
        }
389
390
        if ($user === null) {
391
            $user = $this->getCurrentUserReference();
392
        }
393
394
        // Uses SPI to avoid triggering permission checks in Role/User service
395
        $permissionSets = array();
396
        $roleDomainMapper = $this->getRoleDomainMapper();
397
        $limitationService = $this->getLimitationService();
398
        $spiRoleAssignments = $this->persistenceHandler->userHandler()->loadRoleAssignmentsByGroupId($user->getUserId(), true);
399
        foreach ($spiRoleAssignments as $spiRoleAssignment) {
400
            $permissionSet = array('limitation' => null, 'policies' => array());
401
402
            $spiRole = $this->persistenceHandler->userHandler()->loadRole($spiRoleAssignment->roleId);
403
            foreach ($spiRole->policies as $spiPolicy) {
404
                if ($spiPolicy->module === '*' && $spiRoleAssignment->limitationIdentifier === null) {
405
                    return true;
406
                }
407
408
                if ($spiPolicy->module !== $module && $spiPolicy->module !== '*') {
409
                    continue;
410
                }
411
412
                if ($spiPolicy->function === '*' && $spiRoleAssignment->limitationIdentifier === null) {
413
                    return true;
414
                }
415
416
                if ($spiPolicy->function !== $function && $spiPolicy->function !== '*') {
417
                    continue;
418
                }
419
420
                if ($spiPolicy->limitations === '*' && $spiRoleAssignment->limitationIdentifier === null) {
421
                    return true;
422
                }
423
424
                $permissionSet['policies'][] = $roleDomainMapper->buildDomainPolicyObject($spiPolicy);
425
            }
426
427
            if (!empty($permissionSet['policies'])) {
428
                if ($spiRoleAssignment->limitationIdentifier !== null) {
429
                    $permissionSet['limitation'] = $limitationService
430
                        ->getLimitationType($spiRoleAssignment->limitationIdentifier)
431
                        ->buildValue($spiRoleAssignment->values);
0 ignored issues
show
Bug introduced by
It seems like $spiRoleAssignment->values can also be of type null; however, eZ\Publish\SPI\Limitation\Type::buildValue() does only seem to accept array<integer,*>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
432
                }
433
434
                $permissionSets[] = $permissionSet;
435
            }
436
        }
437
438
        if (!empty($permissionSets)) {
439
            return $permissionSets;
440
        }
441
442
        return false;// No policies matching $module and $function, or they contained limitations
443
    }
444
445
    /**
446
     * Check if user has access to a given action on a given value object.
447
     *
448
     * Indicates if the current user is allowed to perform an action given by the function on the given
449
     * objects.
450
     *
451
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If any of the arguments are invalid
452
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If value of the LimitationValue is unsupported
453
     *
454
     * @param string $module The module, aka controller identifier to check permissions on
455
     * @param string $function The function, aka the controller action to check permissions on
456
     * @param \eZ\Publish\API\Repository\Values\ValueObject $object The object to check if the user has access to
457
     * @param mixed $targets The location, parent or "assignment" value object, or an array of the same
458
     *
459
     * @return bool
460
     */
461
    public function canUser($module, $function, ValueObject $object, $targets = null)
462
    {
463
        $permissionSets = $this->hasAccess($module, $function);
464
        if ($permissionSets === false || $permissionSets === true) {
465
            return $permissionSets;
466
        }
467
468
        if ($targets instanceof ValueObject) {
469
            $targets = array($targets);
470
        } elseif ($targets !== null && !is_array($targets)) {
471
            throw new InvalidArgumentType(
472
                '$targets',
473
                'null|\\eZ\\Publish\\API\\Repository\\Values\\ValueObject|\\eZ\\Publish\\API\\Repository\\Values\\ValueObject[]',
474
                $targets
475
            );
476
        }
477
478
        $limitationService = $this->getLimitationService();
479
        $currentUserRef = $this->getCurrentUserReference();
480
        foreach ($permissionSets as $permissionSet) {
0 ignored issues
show
Bug introduced by
The expression $permissionSets of type boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
481
            /**
482
             * First deal with Role limitation if any.
483
             *
484
             * Here we accept ACCESS_GRANTED and ACCESS_ABSTAIN, the latter in cases where $object and $targets
485
             * are not supported by limitation.
486
             *
487
             * @var \eZ\Publish\API\Repository\Values\User\Limitation[]
488
             */
489
            if ($permissionSet['limitation'] instanceof Limitation) {
490
                $type = $limitationService->getLimitationType($permissionSet['limitation']->getIdentifier());
491
                $accessVote = $type->evaluate($permissionSet['limitation'], $currentUserRef, $object, $targets);
0 ignored issues
show
Bug introduced by
It seems like $targets defined by parameter $targets on line 461 can also be of type array; however, eZ\Publish\SPI\Limitation\Type::evaluate() does only seem to accept null|array<integer,objec...ry\Values\ValueObject>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
492
                if ($accessVote === LimitationType::ACCESS_DENIED) {
493
                    continue;
494
                }
495
            }
496
497
            /**
498
             * Loop over all policies.
499
             *
500
             * These are already filtered by hasAccess and given hasAccess did not return boolean
501
             * there must be some, so only return true if one of them says yes.
502
             *
503
             * @var \eZ\Publish\API\Repository\Values\User\Policy
504
             */
505
            foreach ($permissionSet['policies'] as $policy) {
506
                $limitations = $policy->getLimitations();
507
508
                /*
509
                 * Return true if policy gives full access (aka no limitations)
510
                 */
511
                if ($limitations === '*') {
512
                    return true;
513
                }
514
515
                /*
516
                 * Loop over limitations, all must return ACCESS_GRANTED for policy to pass.
517
                 * If limitations was empty array this means same as '*'
518
                 */
519
                $limitationsPass = true;
520
                foreach ($limitations as $limitation) {
521
                    $type = $limitationService->getLimitationType($limitation->getIdentifier());
522
                    $accessVote = $type->evaluate($limitation, $currentUserRef, $object, $targets);
0 ignored issues
show
Bug introduced by
It seems like $targets defined by parameter $targets on line 461 can also be of type array; however, eZ\Publish\SPI\Limitation\Type::evaluate() does only seem to accept null|array<integer,objec...ry\Values\ValueObject>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
523
                    /*
524
                     * For policy limitation atm only support ACCESS_GRANTED
525
                     *
526
                     * Reasoning: Right now, use of a policy limitation not valid for a policy is per definition a
527
                     * BadState. To reach this you would have to configure the "policyMap" wrongly, like using
528
                     * Node (Location) limitation on state/assign. So in this case Role Limitations will return
529
                     * ACCESS_ABSTAIN (== no access here), and other limitations will throw InvalidArgument above,
530
                     * both cases forcing dev to investigate to find miss configuration. This might be relaxed in
531
                     * the future if valid use cases for ACCESS_ABSTAIN on policy limitations becomes known.
532
                     */
533
                    if ($accessVote !== LimitationType::ACCESS_GRANTED) {
534
                        $limitationsPass = false;
535
                        break;// Break to next policy, all limitations must pass
536
                    }
537
                }
538
                if ($limitationsPass) {
539
                    return true;
540
                }
541
            }
542
        }
543
544
        return false;// None of the limitation sets wanted to let you in, sorry!
545
    }
546
547
    /**
548
     * Get Content Service.
549
     *
550
     * Get service object to perform operations on Content objects and it's aggregate members.
551
     *
552
     * @return \eZ\Publish\API\Repository\ContentService
553
     */
554
    public function getContentService()
555
    {
556
        if ($this->contentService !== null) {
557
            return $this->contentService;
558
        }
559
560
        $this->contentService = new ContentService(
561
            $this,
562
            $this->persistenceHandler,
563
            $this->getDomainMapper(),
564
            $this->getRelationProcessor(),
565
            $this->getNameSchemaService(),
566
            $this->getFieldTypeRegistry(),
567
            $this->serviceSettings['content']
568
        );
569
570
        return $this->contentService;
571
    }
572
573
    /**
574
     * Get Content Language Service.
575
     *
576
     * Get service object to perform operations on Content language objects
577
     *
578
     * @return \eZ\Publish\API\Repository\LanguageService
579
     */
580
    public function getContentLanguageService()
581
    {
582
        if ($this->languageService !== null) {
583
            return $this->languageService;
584
        }
585
586
        $this->languageService = new LanguageService(
587
            $this,
588
            $this->persistenceHandler->contentLanguageHandler(),
589
            $this->serviceSettings['language']
590
        );
591
592
        return $this->languageService;
593
    }
594
595
    /**
596
     * Get Content Type Service.
597
     *
598
     * Get service object to perform operations on Content Type objects and it's aggregate members.
599
     * ( Group, Field & FieldCategory )
600
     *
601
     * @return \eZ\Publish\API\Repository\ContentTypeService
602
     */
603 View Code Duplication
    public function getContentTypeService()
604
    {
605
        if ($this->contentTypeService !== null) {
606
            return $this->contentTypeService;
607
        }
608
609
        $this->contentTypeService = new ContentTypeService(
610
            $this,
611
            $this->persistenceHandler->contentTypeHandler(),
612
            $this->getDomainMapper(),
613
            $this->getFieldTypeRegistry(),
614
            $this->serviceSettings['contentType']
615
        );
616
617
        return $this->contentTypeService;
618
    }
619
620
    /**
621
     * Get Content Location Service.
622
     *
623
     * Get service object to perform operations on Location objects and subtrees
624
     *
625
     * @return \eZ\Publish\API\Repository\LocationService
626
     */
627
    public function getLocationService()
628
    {
629
        if ($this->locationService !== null) {
630
            return $this->locationService;
631
        }
632
633
        $this->locationService = new LocationService(
634
            $this,
635
            $this->persistenceHandler,
636
            $this->getDomainMapper(),
637
            $this->getNameSchemaService(),
638
            $this->getPermissionsCriterionHandler(),
639
            $this->serviceSettings['location']
640
        );
641
642
        return $this->locationService;
643
    }
644
645
    /**
646
     * Get Content Trash service.
647
     *
648
     * Trash service allows to perform operations related to location trash
649
     * (trash/untrash, load/list from trash...)
650
     *
651
     * @return \eZ\Publish\API\Repository\TrashService
652
     */
653
    public function getTrashService()
654
    {
655
        if ($this->trashService !== null) {
656
            return $this->trashService;
657
        }
658
659
        $this->trashService = new TrashService(
660
            $this,
661
            $this->persistenceHandler,
662
            $this->getNameSchemaService(),
663
            $this->serviceSettings['trash']
664
        );
665
666
        return $this->trashService;
667
    }
668
669
    /**
670
     * Get Content Section Service.
671
     *
672
     * Get Section service that lets you manipulate section objects
673
     *
674
     * @return \eZ\Publish\API\Repository\SectionService
675
     */
676
    public function getSectionService()
677
    {
678
        if ($this->sectionService !== null) {
679
            return $this->sectionService;
680
        }
681
682
        $this->sectionService = new SectionService(
683
            $this,
684
            $this->persistenceHandler->sectionHandler(),
685
            $this->serviceSettings['section']
686
        );
687
688
        return $this->sectionService;
689
    }
690
691
    /**
692
     * Get User Service.
693
     *
694
     * Get service object to perform operations on Users and UserGroup
695
     *
696
     * @return \eZ\Publish\API\Repository\UserService
697
     */
698
    public function getUserService()
699
    {
700
        if ($this->userService !== null) {
701
            return $this->userService;
702
        }
703
704
        $this->userService = new UserService(
705
            $this,
706
            $this->persistenceHandler->userHandler(),
707
            $this->serviceSettings['user']
708
        );
709
710
        return $this->userService;
711
    }
712
713
    /**
714
     * Get URLAliasService.
715
     *
716
     * @return \eZ\Publish\API\Repository\URLAliasService
717
     */
718
    public function getURLAliasService()
719
    {
720
        if ($this->urlAliasService !== null) {
721
            return $this->urlAliasService;
722
        }
723
724
        $this->urlAliasService = new URLAliasService(
725
            $this,
726
            $this->persistenceHandler->urlAliasHandler(),
727
            $this->serviceSettings['urlAlias']
728
        );
729
730
        return $this->urlAliasService;
731
    }
732
733
    /**
734
     * Get URLWildcardService.
735
     *
736
     * @return \eZ\Publish\API\Repository\URLWildcardService
737
     */
738
    public function getURLWildcardService()
739
    {
740
        if ($this->urlWildcardService !== null) {
741
            return $this->urlWildcardService;
742
        }
743
744
        $this->urlWildcardService = new URLWildcardService(
745
            $this,
746
            $this->persistenceHandler->urlWildcardHandler(),
747
            $this->serviceSettings['urlWildcard']
748
        );
749
750
        return $this->urlWildcardService;
751
    }
752
753
    /**
754
     * Get ObjectStateService.
755
     *
756
     * @return \eZ\Publish\API\Repository\ObjectStateService
757
     */
758
    public function getObjectStateService()
759
    {
760
        if ($this->objectStateService !== null) {
761
            return $this->objectStateService;
762
        }
763
764
        $this->objectStateService = new ObjectStateService(
765
            $this,
766
            $this->persistenceHandler->objectStateHandler(),
767
            $this->serviceSettings['objectState']
768
        );
769
770
        return $this->objectStateService;
771
    }
772
773
    /**
774
     * Get RoleService.
775
     *
776
     * @return \eZ\Publish\API\Repository\RoleService
777
     */
778
    public function getRoleService()
779
    {
780
        if ($this->roleService !== null) {
781
            return $this->roleService;
782
        }
783
784
        $this->roleService = new RoleService(
785
            $this,
786
            $this->persistenceHandler->userHandler(),
787
            $this->getLimitationService(),
788
            $this->getRoleDomainMapper(),
789
            $this->serviceSettings['role']
790
        );
791
792
        return $this->roleService;
793
    }
794
795
    /**
796
     * Get LimitationService.
797
     *
798
     * @return \eZ\Publish\Core\Repository\Helper\LimitationService
799
     */
800
    protected function getLimitationService()
801
    {
802
        if ($this->limitationService !== null) {
803
            return $this->limitationService;
804
        }
805
806
        $this->limitationService = new Helper\LimitationService($this->serviceSettings['role']);
807
808
        return $this->limitationService;
809
    }
810
811
    /**
812
     * Get RoleDomainMapper.
813
     *
814
     * @return \eZ\Publish\Core\Repository\Helper\RoleDomainMapper
815
     */
816
    protected function getRoleDomainMapper()
817
    {
818
        if ($this->roleDomainMapper !== null) {
819
            return $this->roleDomainMapper;
820
        }
821
822
        $this->roleDomainMapper = new Helper\RoleDomainMapper($this->getLimitationService());
823
824
        return $this->roleDomainMapper;
825
    }
826
827
    /**
828
     * Get SearchService.
829
     *
830
     * @return \eZ\Publish\API\Repository\SearchService
831
     */
832
    public function getSearchService()
833
    {
834
        if ($this->searchService !== null) {
835
            return $this->searchService;
836
        }
837
838
        $this->searchService = new SearchService(
839
            $this,
840
            $this->searchHandler,
841
            $this->getDomainMapper(),
842
            $this->getPermissionsCriterionHandler(),
843
            $this->serviceSettings['search']
844
        );
845
846
        return $this->searchService;
847
    }
848
849
    /**
850
     * Get FieldTypeService.
851
     *
852
     * @return \eZ\Publish\API\Repository\FieldTypeService
853
     */
854
    public function getFieldTypeService()
855
    {
856
        if ($this->fieldTypeService !== null) {
857
            return $this->fieldTypeService;
858
        }
859
860
        $this->fieldTypeService = new FieldTypeService($this->getFieldTypeRegistry());
861
862
        return $this->fieldTypeService;
863
    }
864
865
    /**
866
     * @return Helper\FieldTypeRegistry
867
     */
868
    protected function getFieldTypeRegistry()
869
    {
870
        if ($this->fieldTypeRegistry !== null) {
871
            return $this->fieldTypeRegistry;
872
        }
873
874
        $this->fieldTypeRegistry = new Helper\FieldTypeRegistry($this->serviceSettings['fieldType']);
875
876
        return $this->fieldTypeRegistry;
877
    }
878
879
    /**
880
     * Get NameSchemaResolverService.
881
     *
882
     *
883
     * @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory.
884
     *
885
     * @internal
886
     * @private
887
     *
888
     * @return \eZ\Publish\Core\Repository\Helper\NameSchemaService
889
     */
890 View Code Duplication
    public function getNameSchemaService()
891
    {
892
        if ($this->nameSchemaService !== null) {
893
            return $this->nameSchemaService;
894
        }
895
896
        $this->nameSchemaService = new Helper\NameSchemaService(
897
            $this->persistenceHandler->contentTypeHandler(),
898
            $this->getFieldTypeRegistry(),
899
            $this->serviceSettings['nameSchema']
900
        );
901
902
        return $this->nameSchemaService;
903
    }
904
905
    /**
906
     * Get RelationProcessor.
907
     *
908
     *
909
     * @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory.
910
     *
911
     * @return \eZ\Publish\Core\Repository\Helper\RelationProcessor
912
     */
913
    protected function getRelationProcessor()
914
    {
915
        if ($this->relationProcessor !== null) {
916
            return $this->relationProcessor;
917
        }
918
919
        $this->relationProcessor = new Helper\RelationProcessor($this->persistenceHandler);
920
921
        return $this->relationProcessor;
922
    }
923
924
    /**
925
     * Get RelationProcessor.
926
     *
927
     *
928
     * @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory.
929
     *
930
     * @return \eZ\Publish\Core\Repository\Helper\DomainMapper
931
     */
932
    protected function getDomainMapper()
933
    {
934
        if ($this->domainMapper !== null) {
935
            return $this->domainMapper;
936
        }
937
938
        $this->domainMapper = new Helper\DomainMapper(
939
            $this->persistenceHandler->contentHandler(),
940
            $this->persistenceHandler->locationHandler(),
941
            $this->persistenceHandler->contentTypeHandler(),
942
            $this->persistenceHandler->contentLanguageHandler(),
943
            $this->getFieldTypeRegistry()
944
        );
945
946
        return $this->domainMapper;
947
    }
948
949
    /**
950
     * Get PermissionsCriterionHandler.
951
     *
952
     *
953
     * @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory.
954
     *
955
     * @return \eZ\Publish\Core\Repository\PermissionsCriterionHandler
956
     */
957
    protected function getPermissionsCriterionHandler()
958
    {
959
        return $this->permissionsCriterionHandler !== null ?
960
            $this->permissionsCriterionHandler :
961
            $this->permissionsCriterionHandler = new PermissionsCriterionHandler($this);
962
    }
963
964
    /**
965
     * Begin transaction.
966
     *
967
     * Begins an transaction, make sure you'll call commit or rollback when done,
968
     * otherwise work will be lost.
969
     */
970
    public function beginTransaction()
971
    {
972
        $this->persistenceHandler->beginTransaction();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\SPI\Persisten...ler::beginTransaction() has been deprecated with message: Since 5.3 {@use transactionHandler()->beginTransaction()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
973
974
        ++$this->transactionDepth;
975
        $this->commitEventsQueue[++$this->transactionCount] = array();
976
    }
977
978
    /**
979
     * Commit transaction.
980
     *
981
     * Commit transaction, or throw exceptions if no transactions has been started.
982
     *
983
     * @throws RuntimeException If no transaction has been started
984
     */
985
    public function commit()
986
    {
987
        try {
988
            $this->persistenceHandler->commit();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\SPI\Persistence\Handler::commit() has been deprecated with message: Since 5.3 {@use transactionHandler()->commit()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
989
990
            --$this->transactionDepth;
991
992
            if ($this->transactionDepth === 0) {
993
                $queueCountDown = count($this->commitEventsQueue);
994
                foreach ($this->commitEventsQueue as $eventsQueue) {
995
                    --$queueCountDown;
996
                    if (empty($eventsQueue)) {
997
                        continue;
998
                    }
999
1000
                    $eventCountDown = count($eventsQueue);
1001
                    foreach ($eventsQueue as $event) {
1002
                        --$eventCountDown;
1003
                        // event expects a boolean param, if true it means it is last event (for commit use)
1004
                        $event($queueCountDown === 0 && $eventCountDown === 0);
1005
                    }
1006
                }
1007
1008
                $this->commitEventsQueue = array();
1009
            }
1010
        } catch (Exception $e) {
1011
            throw new RuntimeException($e->getMessage(), 0, $e);
1012
        }
1013
    }
1014
1015
    /**
1016
     * Rollback transaction.
1017
     *
1018
     * Rollback transaction, or throw exceptions if no transactions has been started.
1019
     *
1020
     * @throws RuntimeException If no transaction has been started
1021
     */
1022
    public function rollback()
1023
    {
1024
        try {
1025
            $this->persistenceHandler->rollback();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\SPI\Persistence\Handler::rollback() has been deprecated with message: Since 5.3 {@use transactionHandler()->rollback()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1026
1027
            --$this->transactionDepth;
1028
            unset($this->commitEventsQueue[$this->transactionCount]);
1029
        } catch (Exception $e) {
1030
            throw new RuntimeException($e->getMessage(), 0, $e);
1031
        }
1032
    }
1033
1034
    /**
1035
     * Enqueue an event to be triggered at commit or directly if no transaction has started.
1036
     *
1037
     * @param Callable $event
1038
     */
1039
    public function commitEvent($event)
1040
    {
1041
        if ($this->transactionDepth !== 0) {
1042
            $this->commitEventsQueue[$this->transactionCount][] = $event;
1043
        } else {
1044
            // event expects a boolean param, if true it means it is last event (for commit use)
1045
            $event(true);
1046
        }
1047
    }
1048
1049
    /**
1050
     * Only for internal use.
1051
     *
1052
     * Creates a \DateTime object for $timestamp in the current time zone
1053
     *
1054
     * @param int $timestamp
1055
     *
1056
     * @return \DateTime
1057
     */
1058 View Code Duplication
    public function createDateTime($timestamp = null)
1059
    {
1060
        $dateTime = new \DateTime();
1061
        if ($timestamp !== null) {
1062
            $dateTime->setTimestamp($timestamp);
1063
        }
1064
1065
        return $dateTime;
1066
    }
1067
}
1068