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 NameableFieldTypeRegistry. |
153
|
|
|
* |
154
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\NameableFieldTypeRegistry |
155
|
|
|
*/ |
156
|
|
|
private $nameableFieldTypeRegistry; |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Instance of name schema resolver service. |
160
|
|
|
* |
161
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\NameSchemaService |
162
|
|
|
*/ |
163
|
|
|
protected $nameSchemaService; |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Instance of relation processor service. |
167
|
|
|
* |
168
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\RelationProcessor |
169
|
|
|
*/ |
170
|
|
|
protected $relationProcessor; |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Instance of URL alias service. |
174
|
|
|
* |
175
|
|
|
* @var \eZ\Publish\Core\Repository\URLAliasService |
176
|
|
|
*/ |
177
|
|
|
protected $urlAliasService; |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Instance of URL wildcard service. |
181
|
|
|
* |
182
|
|
|
* @var \eZ\Publish\Core\Repository\URLWildcardService |
183
|
|
|
*/ |
184
|
|
|
protected $urlWildcardService; |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Service settings, first level key is service name. |
188
|
|
|
* |
189
|
|
|
* @var array |
190
|
|
|
*/ |
191
|
|
|
protected $serviceSettings; |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Instance of role service. |
195
|
|
|
* |
196
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\LimitationService |
197
|
|
|
*/ |
198
|
|
|
protected $limitationService; |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\RoleDomainMapper |
202
|
|
|
*/ |
203
|
|
|
protected $roleDomainMapper; |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Instance of domain mapper. |
207
|
|
|
* |
208
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\DomainMapper |
209
|
|
|
*/ |
210
|
|
|
protected $domainMapper; |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Instance of content type domain mapper. |
214
|
|
|
* |
215
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\ContentTypeDomainMapper |
216
|
|
|
*/ |
217
|
|
|
protected $contentTypeDomainMapper; |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Instance of permissions criterion handler. |
221
|
|
|
* |
222
|
|
|
* @var \eZ\Publish\Core\Repository\PermissionsCriterionHandler |
223
|
|
|
*/ |
224
|
|
|
protected $permissionsCriterionHandler; |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Array of arrays of commit events indexed by the transaction count. |
228
|
|
|
* |
229
|
|
|
* @var array |
230
|
|
|
*/ |
231
|
|
|
protected $commitEventsQueue = array(); |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* @var int |
235
|
|
|
*/ |
236
|
|
|
protected $transactionDepth = 0; |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* @var int |
240
|
|
|
*/ |
241
|
|
|
private $transactionCount = 0; |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Constructor. |
245
|
|
|
* |
246
|
|
|
* Construct repository object with provided storage engine |
247
|
|
|
* |
248
|
|
|
* @param \eZ\Publish\SPI\Persistence\Handler $persistenceHandler |
249
|
|
|
* @param \eZ\Publish\SPI\Search\Handler $searchHandler |
250
|
|
|
* @param array $serviceSettings |
251
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference|null $user |
252
|
|
|
*/ |
253
|
|
|
public function __construct( |
254
|
|
|
PersistenceHandler $persistenceHandler, |
255
|
|
|
SearchHandler $searchHandler, |
256
|
|
|
array $serviceSettings = array(), |
257
|
|
|
APIUserReference $user = null |
258
|
|
|
) { |
259
|
|
|
$this->persistenceHandler = $persistenceHandler; |
260
|
|
|
$this->searchHandler = $searchHandler; |
261
|
|
|
$this->serviceSettings = $serviceSettings + array( |
262
|
|
|
'content' => array(), |
263
|
|
|
'contentType' => array(), |
264
|
|
|
'location' => array(), |
265
|
|
|
'section' => array(), |
266
|
|
|
'role' => array(), |
267
|
|
|
'user' => array( |
268
|
|
|
'anonymousUserID' => 10, |
269
|
|
|
), |
270
|
|
|
'language' => array(), |
271
|
|
|
'trash' => array(), |
272
|
|
|
'io' => array(), |
273
|
|
|
'objectState' => array(), |
274
|
|
|
'search' => array(), |
275
|
|
|
'fieldType' => array(), |
276
|
|
|
'nameableFieldTypes' => array(), |
277
|
|
|
'urlAlias' => array(), |
278
|
|
|
'urlWildcard' => array(), |
279
|
|
|
'nameSchema' => array(), |
280
|
|
|
'languages' => array(), |
281
|
|
|
); |
282
|
|
|
|
283
|
|
|
if (!empty($this->serviceSettings['languages'])) { |
284
|
|
|
$this->serviceSettings['language']['languages'] = $this->serviceSettings['languages']; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
if ($user instanceof User) { |
288
|
|
|
$this->currentUser = $user; |
289
|
|
|
$this->currentUserRef = new UserReference($user->getUserId()); |
290
|
|
|
} elseif ($user instanceof APIUserReference) { |
291
|
|
|
$this->currentUserRef = $user; |
292
|
|
|
} else { |
293
|
|
|
$this->currentUserRef = new UserReference($this->serviceSettings['user']['anonymousUserID']); |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* Get current user. |
299
|
|
|
* |
300
|
|
|
* Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()} |
301
|
|
|
* |
302
|
|
|
* @return \eZ\Publish\API\Repository\Values\User\User |
303
|
|
|
*/ |
304
|
|
|
public function getCurrentUser() |
305
|
|
|
{ |
306
|
|
|
if ($this->currentUser === null) { |
307
|
|
|
$this->currentUser = $this->getUserService()->loadUser( |
308
|
|
|
$this->currentUserRef->getUserId() |
309
|
|
|
); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
return $this->currentUser; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Get current user reference. |
317
|
|
|
* |
318
|
|
|
* @since 5.4.5 |
319
|
|
|
* @return \eZ\Publish\API\Repository\Values\User\UserReference |
320
|
|
|
*/ |
321
|
|
|
public function getCurrentUserReference() |
322
|
|
|
{ |
323
|
|
|
return $this->currentUserRef; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Sets the current user to the given $user. |
328
|
|
|
* |
329
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference $user |
330
|
|
|
* |
331
|
|
|
* @throws InvalidArgumentValue If UserReference does not contain a id |
332
|
|
|
*/ |
333
|
|
|
public function setCurrentUser(APIUserReference $user) |
334
|
|
|
{ |
335
|
|
|
$id = $user->getUserId(); |
336
|
|
|
if (!$id) { |
337
|
|
|
throw new InvalidArgumentValue('$user->getUserId()', $id); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
if ($user instanceof User) { |
341
|
|
|
$this->currentUser = $user; |
342
|
|
|
$this->currentUserRef = new UserReference($id); |
343
|
|
|
} else { |
344
|
|
|
$this->currentUser = null; |
345
|
|
|
$this->currentUserRef = $user; |
346
|
|
|
} |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Allows API execution to be performed with full access sand-boxed. |
351
|
|
|
* |
352
|
|
|
* The closure sandbox will do a catch all on exceptions and rethrow after |
353
|
|
|
* re-setting the sudo flag. |
354
|
|
|
* |
355
|
|
|
* Example use: |
356
|
|
|
* $location = $repository->sudo( |
357
|
|
|
* function ( Repository $repo ) use ( $locationId ) |
358
|
|
|
* { |
359
|
|
|
* return $repo->getLocationService()->loadLocation( $locationId ) |
360
|
|
|
* } |
361
|
|
|
* ); |
362
|
|
|
* |
363
|
|
|
* |
364
|
|
|
* @param \Closure $callback |
365
|
|
|
* @param \eZ\Publish\API\Repository\Repository $outerRepository |
366
|
|
|
* |
367
|
|
|
* @throws \RuntimeException Thrown on recursive sudo() use. |
368
|
|
|
* @throws \Exception Re throws exceptions thrown inside $callback |
369
|
|
|
* |
370
|
|
|
* @return mixed |
371
|
|
|
*/ |
372
|
|
|
public function sudo(\Closure $callback, RepositoryInterface $outerRepository = null) |
373
|
|
|
{ |
374
|
|
|
++$this->sudoNestingLevel; |
375
|
|
|
try { |
376
|
|
|
$returnValue = $callback($outerRepository !== null ? $outerRepository : $this); |
377
|
|
|
} catch (Exception $e) { |
378
|
|
|
--$this->sudoNestingLevel; |
379
|
|
|
throw $e; |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
--$this->sudoNestingLevel; |
383
|
|
|
|
384
|
|
|
return $returnValue; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* Check if user has access to a given module / function. |
389
|
|
|
* |
390
|
|
|
* Low level function, use canUser instead if you have objects to check against. |
391
|
|
|
* |
392
|
|
|
* @param string $module |
393
|
|
|
* @param string $function |
394
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference $user |
395
|
|
|
* |
396
|
|
|
* @return bool|array Bool if user has full or no access, array if limitations if not |
397
|
|
|
*/ |
398
|
|
|
public function hasAccess($module, $function, APIUserReference $user = null) |
399
|
|
|
{ |
400
|
|
|
// Full access if sudo nesting level is set by {@see sudo()} |
401
|
|
|
if ($this->sudoNestingLevel > 0) { |
402
|
|
|
return true; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
if ($user === null) { |
406
|
|
|
$user = $this->getCurrentUserReference(); |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
// Uses SPI to avoid triggering permission checks in Role/User service |
410
|
|
|
$permissionSets = array(); |
411
|
|
|
$roleDomainMapper = $this->getRoleDomainMapper(); |
412
|
|
|
$limitationService = $this->getLimitationService(); |
413
|
|
|
$spiRoleAssignments = $this->persistenceHandler->userHandler()->loadRoleAssignmentsByGroupId($user->getUserId(), true); |
414
|
|
|
foreach ($spiRoleAssignments as $spiRoleAssignment) { |
415
|
|
|
$permissionSet = array('limitation' => null, 'policies' => array()); |
416
|
|
|
|
417
|
|
|
$spiRole = $this->persistenceHandler->userHandler()->loadRole($spiRoleAssignment->roleId); |
418
|
|
|
foreach ($spiRole->policies as $spiPolicy) { |
419
|
|
|
if ($spiPolicy->module === '*' && $spiRoleAssignment->limitationIdentifier === null) { |
420
|
|
|
return true; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
if ($spiPolicy->module !== $module && $spiPolicy->module !== '*') { |
424
|
|
|
continue; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
if ($spiPolicy->function === '*' && $spiRoleAssignment->limitationIdentifier === null) { |
428
|
|
|
return true; |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
if ($spiPolicy->function !== $function && $spiPolicy->function !== '*') { |
432
|
|
|
continue; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
if ($spiPolicy->limitations === '*' && $spiRoleAssignment->limitationIdentifier === null) { |
436
|
|
|
return true; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
$permissionSet['policies'][] = $roleDomainMapper->buildDomainPolicyObject($spiPolicy); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
if (!empty($permissionSet['policies'])) { |
443
|
|
|
if ($spiRoleAssignment->limitationIdentifier !== null) { |
444
|
|
|
$permissionSet['limitation'] = $limitationService |
445
|
|
|
->getLimitationType($spiRoleAssignment->limitationIdentifier) |
446
|
|
|
->buildValue($spiRoleAssignment->values); |
|
|
|
|
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
$permissionSets[] = $permissionSet; |
450
|
|
|
} |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
if (!empty($permissionSets)) { |
454
|
|
|
return $permissionSets; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
return false;// No policies matching $module and $function, or they contained limitations |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* Check if user has access to a given action on a given value object. |
462
|
|
|
* |
463
|
|
|
* Indicates if the current user is allowed to perform an action given by the function on the given |
464
|
|
|
* objects. |
465
|
|
|
* |
466
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If any of the arguments are invalid |
467
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException If value of the LimitationValue is unsupported |
468
|
|
|
* |
469
|
|
|
* @param string $module The module, aka controller identifier to check permissions on |
470
|
|
|
* @param string $function The function, aka the controller action to check permissions on |
471
|
|
|
* @param \eZ\Publish\API\Repository\Values\ValueObject $object The object to check if the user has access to |
472
|
|
|
* @param mixed $targets The location, parent or "assignment" value object, or an array of the same |
473
|
|
|
* |
474
|
|
|
* @return bool |
475
|
|
|
*/ |
476
|
|
|
public function canUser($module, $function, ValueObject $object, $targets = null) |
477
|
|
|
{ |
478
|
|
|
$permissionSets = $this->hasAccess($module, $function); |
479
|
|
|
if ($permissionSets === false || $permissionSets === true) { |
480
|
|
|
return $permissionSets; |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
if ($targets instanceof ValueObject) { |
484
|
|
|
$targets = array($targets); |
485
|
|
|
} elseif ($targets !== null && !is_array($targets)) { |
486
|
|
|
throw new InvalidArgumentType( |
487
|
|
|
'$targets', |
488
|
|
|
'null|\\eZ\\Publish\\API\\Repository\\Values\\ValueObject|\\eZ\\Publish\\API\\Repository\\Values\\ValueObject[]', |
489
|
|
|
$targets |
490
|
|
|
); |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
$limitationService = $this->getLimitationService(); |
494
|
|
|
$currentUserRef = $this->getCurrentUserReference(); |
495
|
|
|
foreach ($permissionSets as $permissionSet) { |
|
|
|
|
496
|
|
|
/** |
497
|
|
|
* First deal with Role limitation if any. |
498
|
|
|
* |
499
|
|
|
* Here we accept ACCESS_GRANTED and ACCESS_ABSTAIN, the latter in cases where $object and $targets |
500
|
|
|
* are not supported by limitation. |
501
|
|
|
* |
502
|
|
|
* @var \eZ\Publish\API\Repository\Values\User\Limitation[] |
503
|
|
|
*/ |
504
|
|
|
if ($permissionSet['limitation'] instanceof Limitation) { |
505
|
|
|
$type = $limitationService->getLimitationType($permissionSet['limitation']->getIdentifier()); |
506
|
|
|
$accessVote = $type->evaluate($permissionSet['limitation'], $currentUserRef, $object, $targets); |
|
|
|
|
507
|
|
|
if ($accessVote === LimitationType::ACCESS_DENIED) { |
508
|
|
|
continue; |
509
|
|
|
} |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* Loop over all policies. |
514
|
|
|
* |
515
|
|
|
* These are already filtered by hasAccess and given hasAccess did not return boolean |
516
|
|
|
* there must be some, so only return true if one of them says yes. |
517
|
|
|
* |
518
|
|
|
* @var \eZ\Publish\API\Repository\Values\User\Policy |
519
|
|
|
*/ |
520
|
|
|
foreach ($permissionSet['policies'] as $policy) { |
521
|
|
|
$limitations = $policy->getLimitations(); |
522
|
|
|
|
523
|
|
|
/* |
524
|
|
|
* Return true if policy gives full access (aka no limitations) |
525
|
|
|
*/ |
526
|
|
|
if ($limitations === '*') { |
527
|
|
|
return true; |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
/* |
531
|
|
|
* Loop over limitations, all must return ACCESS_GRANTED for policy to pass. |
532
|
|
|
* If limitations was empty array this means same as '*' |
533
|
|
|
*/ |
534
|
|
|
$limitationsPass = true; |
535
|
|
|
foreach ($limitations as $limitation) { |
536
|
|
|
$type = $limitationService->getLimitationType($limitation->getIdentifier()); |
537
|
|
|
$accessVote = $type->evaluate($limitation, $currentUserRef, $object, $targets); |
|
|
|
|
538
|
|
|
/* |
539
|
|
|
* For policy limitation atm only support ACCESS_GRANTED |
540
|
|
|
* |
541
|
|
|
* Reasoning: Right now, use of a policy limitation not valid for a policy is per definition a |
542
|
|
|
* BadState. To reach this you would have to configure the "policyMap" wrongly, like using |
543
|
|
|
* Node (Location) limitation on state/assign. So in this case Role Limitations will return |
544
|
|
|
* ACCESS_ABSTAIN (== no access here), and other limitations will throw InvalidArgument above, |
545
|
|
|
* both cases forcing dev to investigate to find miss configuration. This might be relaxed in |
546
|
|
|
* the future if valid use cases for ACCESS_ABSTAIN on policy limitations becomes known. |
547
|
|
|
*/ |
548
|
|
|
if ($accessVote !== LimitationType::ACCESS_GRANTED) { |
549
|
|
|
$limitationsPass = false; |
550
|
|
|
break;// Break to next policy, all limitations must pass |
551
|
|
|
} |
552
|
|
|
} |
553
|
|
|
if ($limitationsPass) { |
554
|
|
|
return true; |
555
|
|
|
} |
556
|
|
|
} |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
return false;// None of the limitation sets wanted to let you in, sorry! |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
/** |
563
|
|
|
* Get Content Service. |
564
|
|
|
* |
565
|
|
|
* Get service object to perform operations on Content objects and it's aggregate members. |
566
|
|
|
* |
567
|
|
|
* @return \eZ\Publish\API\Repository\ContentService |
568
|
|
|
*/ |
569
|
|
View Code Duplication |
public function getContentService() |
570
|
|
|
{ |
571
|
|
|
if ($this->contentService !== null) { |
572
|
|
|
return $this->contentService; |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
$this->contentService = new ContentService( |
576
|
|
|
$this, |
577
|
|
|
$this->persistenceHandler, |
578
|
|
|
$this->getDomainMapper(), |
579
|
|
|
$this->getRelationProcessor(), |
580
|
|
|
$this->getNameSchemaService(), |
581
|
|
|
$this->getFieldTypeRegistry(), |
582
|
|
|
$this->serviceSettings['content'] |
583
|
|
|
); |
584
|
|
|
|
585
|
|
|
return $this->contentService; |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* Get Content Language Service. |
590
|
|
|
* |
591
|
|
|
* Get service object to perform operations on Content language objects |
592
|
|
|
* |
593
|
|
|
* @return \eZ\Publish\API\Repository\LanguageService |
594
|
|
|
*/ |
595
|
|
|
public function getContentLanguageService() |
596
|
|
|
{ |
597
|
|
|
if ($this->languageService !== null) { |
598
|
|
|
return $this->languageService; |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
$this->languageService = new LanguageService( |
602
|
|
|
$this, |
603
|
|
|
$this->persistenceHandler->contentLanguageHandler(), |
604
|
|
|
$this->serviceSettings['language'] |
605
|
|
|
); |
606
|
|
|
|
607
|
|
|
return $this->languageService; |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
/** |
611
|
|
|
* Get Content Type Service. |
612
|
|
|
* |
613
|
|
|
* Get service object to perform operations on Content Type objects and it's aggregate members. |
614
|
|
|
* ( Group, Field & FieldCategory ) |
615
|
|
|
* |
616
|
|
|
* @return \eZ\Publish\API\Repository\ContentTypeService |
617
|
|
|
*/ |
618
|
|
View Code Duplication |
public function getContentTypeService() |
619
|
|
|
{ |
620
|
|
|
if ($this->contentTypeService !== null) { |
621
|
|
|
return $this->contentTypeService; |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
$this->contentTypeService = new ContentTypeService( |
625
|
|
|
$this, |
626
|
|
|
$this->persistenceHandler->contentTypeHandler(), |
627
|
|
|
$this->getDomainMapper(), |
628
|
|
|
$this->getContentTypeDomainMapper(), |
629
|
|
|
$this->getFieldTypeRegistry(), |
630
|
|
|
$this->serviceSettings['contentType'] |
631
|
|
|
); |
632
|
|
|
|
633
|
|
|
return $this->contentTypeService; |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* Get Content Location Service. |
638
|
|
|
* |
639
|
|
|
* Get service object to perform operations on Location objects and subtrees |
640
|
|
|
* |
641
|
|
|
* @return \eZ\Publish\API\Repository\LocationService |
642
|
|
|
*/ |
643
|
|
|
public function getLocationService() |
644
|
|
|
{ |
645
|
|
|
if ($this->locationService !== null) { |
646
|
|
|
return $this->locationService; |
647
|
|
|
} |
648
|
|
|
|
649
|
|
|
$this->locationService = new LocationService( |
650
|
|
|
$this, |
651
|
|
|
$this->persistenceHandler, |
652
|
|
|
$this->getDomainMapper(), |
653
|
|
|
$this->getNameSchemaService(), |
654
|
|
|
$this->getPermissionsCriterionHandler(), |
655
|
|
|
$this->serviceSettings['location'] |
656
|
|
|
); |
657
|
|
|
|
658
|
|
|
return $this->locationService; |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
/** |
662
|
|
|
* Get Content Trash service. |
663
|
|
|
* |
664
|
|
|
* Trash service allows to perform operations related to location trash |
665
|
|
|
* (trash/untrash, load/list from trash...) |
666
|
|
|
* |
667
|
|
|
* @return \eZ\Publish\API\Repository\TrashService |
668
|
|
|
*/ |
669
|
|
|
public function getTrashService() |
670
|
|
|
{ |
671
|
|
|
if ($this->trashService !== null) { |
672
|
|
|
return $this->trashService; |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
$this->trashService = new TrashService( |
676
|
|
|
$this, |
677
|
|
|
$this->persistenceHandler, |
678
|
|
|
$this->getNameSchemaService(), |
679
|
|
|
$this->serviceSettings['trash'] |
680
|
|
|
); |
681
|
|
|
|
682
|
|
|
return $this->trashService; |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* Get Content Section Service. |
687
|
|
|
* |
688
|
|
|
* Get Section service that lets you manipulate section objects |
689
|
|
|
* |
690
|
|
|
* @return \eZ\Publish\API\Repository\SectionService |
691
|
|
|
*/ |
692
|
|
|
public function getSectionService() |
693
|
|
|
{ |
694
|
|
|
if ($this->sectionService !== null) { |
695
|
|
|
return $this->sectionService; |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
$this->sectionService = new SectionService( |
699
|
|
|
$this, |
700
|
|
|
$this->persistenceHandler->sectionHandler(), |
701
|
|
|
$this->serviceSettings['section'] |
702
|
|
|
); |
703
|
|
|
|
704
|
|
|
return $this->sectionService; |
705
|
|
|
} |
706
|
|
|
|
707
|
|
|
/** |
708
|
|
|
* Get User Service. |
709
|
|
|
* |
710
|
|
|
* Get service object to perform operations on Users and UserGroup |
711
|
|
|
* |
712
|
|
|
* @return \eZ\Publish\API\Repository\UserService |
713
|
|
|
*/ |
714
|
|
|
public function getUserService() |
715
|
|
|
{ |
716
|
|
|
if ($this->userService !== null) { |
717
|
|
|
return $this->userService; |
718
|
|
|
} |
719
|
|
|
|
720
|
|
|
$this->userService = new UserService( |
721
|
|
|
$this, |
722
|
|
|
$this->persistenceHandler->userHandler(), |
723
|
|
|
$this->serviceSettings['user'] |
724
|
|
|
); |
725
|
|
|
|
726
|
|
|
return $this->userService; |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
/** |
730
|
|
|
* Get URLAliasService. |
731
|
|
|
* |
732
|
|
|
* @return \eZ\Publish\API\Repository\URLAliasService |
733
|
|
|
*/ |
734
|
|
|
public function getURLAliasService() |
735
|
|
|
{ |
736
|
|
|
if ($this->urlAliasService !== null) { |
737
|
|
|
return $this->urlAliasService; |
738
|
|
|
} |
739
|
|
|
|
740
|
|
|
$this->urlAliasService = new URLAliasService( |
741
|
|
|
$this, |
742
|
|
|
$this->persistenceHandler->urlAliasHandler(), |
743
|
|
|
$this->serviceSettings['urlAlias'] |
744
|
|
|
); |
745
|
|
|
|
746
|
|
|
return $this->urlAliasService; |
747
|
|
|
} |
748
|
|
|
|
749
|
|
|
/** |
750
|
|
|
* Get URLWildcardService. |
751
|
|
|
* |
752
|
|
|
* @return \eZ\Publish\API\Repository\URLWildcardService |
753
|
|
|
*/ |
754
|
|
|
public function getURLWildcardService() |
755
|
|
|
{ |
756
|
|
|
if ($this->urlWildcardService !== null) { |
757
|
|
|
return $this->urlWildcardService; |
758
|
|
|
} |
759
|
|
|
|
760
|
|
|
$this->urlWildcardService = new URLWildcardService( |
761
|
|
|
$this, |
762
|
|
|
$this->persistenceHandler->urlWildcardHandler(), |
763
|
|
|
$this->serviceSettings['urlWildcard'] |
764
|
|
|
); |
765
|
|
|
|
766
|
|
|
return $this->urlWildcardService; |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
/** |
770
|
|
|
* Get ObjectStateService. |
771
|
|
|
* |
772
|
|
|
* @return \eZ\Publish\API\Repository\ObjectStateService |
773
|
|
|
*/ |
774
|
|
|
public function getObjectStateService() |
775
|
|
|
{ |
776
|
|
|
if ($this->objectStateService !== null) { |
777
|
|
|
return $this->objectStateService; |
778
|
|
|
} |
779
|
|
|
|
780
|
|
|
$this->objectStateService = new ObjectStateService( |
781
|
|
|
$this, |
782
|
|
|
$this->persistenceHandler->objectStateHandler(), |
783
|
|
|
$this->serviceSettings['objectState'] |
784
|
|
|
); |
785
|
|
|
|
786
|
|
|
return $this->objectStateService; |
787
|
|
|
} |
788
|
|
|
|
789
|
|
|
/** |
790
|
|
|
* Get RoleService. |
791
|
|
|
* |
792
|
|
|
* @return \eZ\Publish\API\Repository\RoleService |
793
|
|
|
*/ |
794
|
|
|
public function getRoleService() |
795
|
|
|
{ |
796
|
|
|
if ($this->roleService !== null) { |
797
|
|
|
return $this->roleService; |
798
|
|
|
} |
799
|
|
|
|
800
|
|
|
$this->roleService = new RoleService( |
801
|
|
|
$this, |
802
|
|
|
$this->persistenceHandler->userHandler(), |
803
|
|
|
$this->getLimitationService(), |
804
|
|
|
$this->getRoleDomainMapper(), |
805
|
|
|
$this->serviceSettings['role'] |
806
|
|
|
); |
807
|
|
|
|
808
|
|
|
return $this->roleService; |
809
|
|
|
} |
810
|
|
|
|
811
|
|
|
/** |
812
|
|
|
* Get LimitationService. |
813
|
|
|
* |
814
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\LimitationService |
815
|
|
|
*/ |
816
|
|
|
protected function getLimitationService() |
817
|
|
|
{ |
818
|
|
|
if ($this->limitationService !== null) { |
819
|
|
|
return $this->limitationService; |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
$this->limitationService = new Helper\LimitationService($this->serviceSettings['role']); |
823
|
|
|
|
824
|
|
|
return $this->limitationService; |
825
|
|
|
} |
826
|
|
|
|
827
|
|
|
/** |
828
|
|
|
* Get RoleDomainMapper. |
829
|
|
|
* |
830
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\RoleDomainMapper |
831
|
|
|
*/ |
832
|
|
|
protected function getRoleDomainMapper() |
833
|
|
|
{ |
834
|
|
|
if ($this->roleDomainMapper !== null) { |
835
|
|
|
return $this->roleDomainMapper; |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
$this->roleDomainMapper = new Helper\RoleDomainMapper($this->getLimitationService()); |
839
|
|
|
|
840
|
|
|
return $this->roleDomainMapper; |
841
|
|
|
} |
842
|
|
|
|
843
|
|
|
/** |
844
|
|
|
* Get SearchService. |
845
|
|
|
* |
846
|
|
|
* @return \eZ\Publish\API\Repository\SearchService |
847
|
|
|
*/ |
848
|
|
|
public function getSearchService() |
849
|
|
|
{ |
850
|
|
|
if ($this->searchService !== null) { |
851
|
|
|
return $this->searchService; |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
$this->searchService = new SearchService( |
855
|
|
|
$this, |
856
|
|
|
$this->searchHandler, |
857
|
|
|
$this->getDomainMapper(), |
858
|
|
|
$this->getPermissionsCriterionHandler(), |
859
|
|
|
$this->serviceSettings['search'] |
860
|
|
|
); |
861
|
|
|
|
862
|
|
|
return $this->searchService; |
863
|
|
|
} |
864
|
|
|
|
865
|
|
|
/** |
866
|
|
|
* Get FieldTypeService. |
867
|
|
|
* |
868
|
|
|
* @return \eZ\Publish\API\Repository\FieldTypeService |
869
|
|
|
*/ |
870
|
|
|
public function getFieldTypeService() |
871
|
|
|
{ |
872
|
|
|
if ($this->fieldTypeService !== null) { |
873
|
|
|
return $this->fieldTypeService; |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
$this->fieldTypeService = new FieldTypeService($this->getFieldTypeRegistry()); |
877
|
|
|
|
878
|
|
|
return $this->fieldTypeService; |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
/** |
882
|
|
|
* @return Helper\FieldTypeRegistry |
883
|
|
|
*/ |
884
|
|
|
protected function getFieldTypeRegistry() |
885
|
|
|
{ |
886
|
|
|
if ($this->fieldTypeRegistry !== null) { |
887
|
|
|
return $this->fieldTypeRegistry; |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
$this->fieldTypeRegistry = new Helper\FieldTypeRegistry($this->serviceSettings['fieldType']); |
891
|
|
|
|
892
|
|
|
return $this->fieldTypeRegistry; |
893
|
|
|
} |
894
|
|
|
|
895
|
|
|
/** |
896
|
|
|
* @return Helper\NameableFieldTypeRegistry |
897
|
|
|
*/ |
898
|
|
|
protected function getNameableFieldTypeRegistry() |
899
|
|
|
{ |
900
|
|
|
if ($this->nameableFieldTypeRegistry !== null) { |
901
|
|
|
return $this->nameableFieldTypeRegistry; |
902
|
|
|
} |
903
|
|
|
|
904
|
|
|
$this->nameableFieldTypeRegistry = new Helper\NameableFieldTypeRegistry($this->serviceSettings['nameableFieldTypes']); |
905
|
|
|
|
906
|
|
|
return $this->nameableFieldTypeRegistry; |
907
|
|
|
} |
908
|
|
|
|
909
|
|
|
/** |
910
|
|
|
* Get NameSchemaResolverService. |
911
|
|
|
* |
912
|
|
|
* |
913
|
|
|
* @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory. |
914
|
|
|
* |
915
|
|
|
* @internal |
916
|
|
|
* @private |
917
|
|
|
* |
918
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\NameSchemaService |
919
|
|
|
*/ |
920
|
|
|
public function getNameSchemaService() |
921
|
|
|
{ |
922
|
|
|
if ($this->nameSchemaService !== null) { |
923
|
|
|
return $this->nameSchemaService; |
924
|
|
|
} |
925
|
|
|
|
926
|
|
|
$this->nameSchemaService = new Helper\NameSchemaService( |
927
|
|
|
$this->persistenceHandler->contentTypeHandler(), |
928
|
|
|
$this->getContentTypeDomainMapper(), |
929
|
|
|
$this->getNameableFieldTypeRegistry(), |
930
|
|
|
$this->serviceSettings['nameSchema'] |
931
|
|
|
); |
932
|
|
|
|
933
|
|
|
return $this->nameSchemaService; |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
/** |
937
|
|
|
* Get RelationProcessor. |
938
|
|
|
* |
939
|
|
|
* |
940
|
|
|
* @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory. |
941
|
|
|
* |
942
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\RelationProcessor |
943
|
|
|
*/ |
944
|
|
|
protected function getRelationProcessor() |
945
|
|
|
{ |
946
|
|
|
if ($this->relationProcessor !== null) { |
947
|
|
|
return $this->relationProcessor; |
948
|
|
|
} |
949
|
|
|
|
950
|
|
|
$this->relationProcessor = new Helper\RelationProcessor($this->persistenceHandler); |
951
|
|
|
|
952
|
|
|
return $this->relationProcessor; |
953
|
|
|
} |
954
|
|
|
|
955
|
|
|
/** |
956
|
|
|
* Get Content Domain Mapper. |
957
|
|
|
* |
958
|
|
|
* @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory. |
959
|
|
|
* |
960
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\DomainMapper |
961
|
|
|
*/ |
962
|
|
|
protected function getDomainMapper() |
963
|
|
|
{ |
964
|
|
|
if ($this->domainMapper !== null) { |
965
|
|
|
return $this->domainMapper; |
966
|
|
|
} |
967
|
|
|
|
968
|
|
|
$this->domainMapper = new Helper\DomainMapper( |
969
|
|
|
$this->persistenceHandler->contentHandler(), |
970
|
|
|
$this->persistenceHandler->locationHandler(), |
971
|
|
|
$this->persistenceHandler->contentTypeHandler(), |
972
|
|
|
$this->persistenceHandler->contentLanguageHandler(), |
973
|
|
|
$this->getFieldTypeRegistry() |
974
|
|
|
); |
975
|
|
|
|
976
|
|
|
return $this->domainMapper; |
977
|
|
|
} |
978
|
|
|
|
979
|
|
|
/** |
980
|
|
|
* Get ContentType Domain Mapper. |
981
|
|
|
* |
982
|
|
|
* @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory. |
983
|
|
|
* |
984
|
|
|
* @return \eZ\Publish\Core\Repository\Helper\ContentTypeDomainMapper |
985
|
|
|
*/ |
986
|
|
|
protected function getContentTypeDomainMapper() |
987
|
|
|
{ |
988
|
|
|
if ($this->contentTypeDomainMapper !== null) { |
989
|
|
|
return $this->contentTypeDomainMapper; |
990
|
|
|
} |
991
|
|
|
|
992
|
|
|
$this->contentTypeDomainMapper = new Helper\ContentTypeDomainMapper( |
993
|
|
|
$this->persistenceHandler->contentLanguageHandler(), |
994
|
|
|
$this->getFieldTypeRegistry() |
995
|
|
|
); |
996
|
|
|
|
997
|
|
|
return $this->contentTypeDomainMapper; |
998
|
|
|
} |
999
|
|
|
|
1000
|
|
|
/** |
1001
|
|
|
* Get PermissionsCriterionHandler. |
1002
|
|
|
* |
1003
|
|
|
* |
1004
|
|
|
* @todo Move out from this & other repo instances when services becomes proper services in DIC terms using factory. |
1005
|
|
|
* |
1006
|
|
|
* @return \eZ\Publish\Core\Repository\PermissionsCriterionHandler |
1007
|
|
|
*/ |
1008
|
|
|
protected function getPermissionsCriterionHandler() |
1009
|
|
|
{ |
1010
|
|
|
return $this->permissionsCriterionHandler !== null ? |
1011
|
|
|
$this->permissionsCriterionHandler : |
1012
|
|
|
$this->permissionsCriterionHandler = new PermissionsCriterionHandler($this); |
1013
|
|
|
} |
1014
|
|
|
|
1015
|
|
|
/** |
1016
|
|
|
* Begin transaction. |
1017
|
|
|
* |
1018
|
|
|
* Begins an transaction, make sure you'll call commit or rollback when done, |
1019
|
|
|
* otherwise work will be lost. |
1020
|
|
|
*/ |
1021
|
|
|
public function beginTransaction() |
1022
|
|
|
{ |
1023
|
|
|
$this->persistenceHandler->beginTransaction(); |
|
|
|
|
1024
|
|
|
|
1025
|
|
|
++$this->transactionDepth; |
1026
|
|
|
$this->commitEventsQueue[++$this->transactionCount] = array(); |
1027
|
|
|
} |
1028
|
|
|
|
1029
|
|
|
/** |
1030
|
|
|
* Commit transaction. |
1031
|
|
|
* |
1032
|
|
|
* Commit transaction, or throw exceptions if no transactions has been started. |
1033
|
|
|
* |
1034
|
|
|
* @throws RuntimeException If no transaction has been started |
1035
|
|
|
*/ |
1036
|
|
|
public function commit() |
1037
|
|
|
{ |
1038
|
|
|
try { |
1039
|
|
|
$this->persistenceHandler->commit(); |
|
|
|
|
1040
|
|
|
|
1041
|
|
|
--$this->transactionDepth; |
1042
|
|
|
|
1043
|
|
|
if ($this->transactionDepth === 0) { |
1044
|
|
|
$queueCountDown = count($this->commitEventsQueue); |
1045
|
|
|
foreach ($this->commitEventsQueue as $eventsQueue) { |
1046
|
|
|
--$queueCountDown; |
1047
|
|
|
if (empty($eventsQueue)) { |
1048
|
|
|
continue; |
1049
|
|
|
} |
1050
|
|
|
|
1051
|
|
|
$eventCountDown = count($eventsQueue); |
1052
|
|
|
foreach ($eventsQueue as $event) { |
1053
|
|
|
--$eventCountDown; |
1054
|
|
|
// event expects a boolean param, if true it means it is last event (for commit use) |
1055
|
|
|
$event($queueCountDown === 0 && $eventCountDown === 0); |
1056
|
|
|
} |
1057
|
|
|
} |
1058
|
|
|
|
1059
|
|
|
$this->commitEventsQueue = array(); |
1060
|
|
|
} |
1061
|
|
|
} catch (Exception $e) { |
1062
|
|
|
throw new RuntimeException($e->getMessage(), 0, $e); |
1063
|
|
|
} |
1064
|
|
|
} |
1065
|
|
|
|
1066
|
|
|
/** |
1067
|
|
|
* Rollback transaction. |
1068
|
|
|
* |
1069
|
|
|
* Rollback transaction, or throw exceptions if no transactions has been started. |
1070
|
|
|
* |
1071
|
|
|
* @throws RuntimeException If no transaction has been started |
1072
|
|
|
*/ |
1073
|
|
|
public function rollback() |
1074
|
|
|
{ |
1075
|
|
|
try { |
1076
|
|
|
$this->persistenceHandler->rollback(); |
|
|
|
|
1077
|
|
|
|
1078
|
|
|
--$this->transactionDepth; |
1079
|
|
|
unset($this->commitEventsQueue[$this->transactionCount]); |
1080
|
|
|
} catch (Exception $e) { |
1081
|
|
|
throw new RuntimeException($e->getMessage(), 0, $e); |
1082
|
|
|
} |
1083
|
|
|
} |
1084
|
|
|
|
1085
|
|
|
/** |
1086
|
|
|
* Enqueue an event to be triggered at commit or directly if no transaction has started. |
1087
|
|
|
* |
1088
|
|
|
* @param Callable $event |
1089
|
|
|
*/ |
1090
|
|
|
public function commitEvent($event) |
1091
|
|
|
{ |
1092
|
|
|
if ($this->transactionDepth !== 0) { |
1093
|
|
|
$this->commitEventsQueue[$this->transactionCount][] = $event; |
1094
|
|
|
} else { |
1095
|
|
|
// event expects a boolean param, if true it means it is last event (for commit use) |
1096
|
|
|
$event(true); |
1097
|
|
|
} |
1098
|
|
|
} |
1099
|
|
|
|
1100
|
|
|
/** |
1101
|
|
|
* Only for internal use. |
1102
|
|
|
* |
1103
|
|
|
* Creates a \DateTime object for $timestamp in the current time zone |
1104
|
|
|
* |
1105
|
|
|
* @param int $timestamp |
1106
|
|
|
* |
1107
|
|
|
* @return \DateTime |
1108
|
|
|
*/ |
1109
|
|
View Code Duplication |
public function createDateTime($timestamp = null) |
1110
|
|
|
{ |
1111
|
|
|
$dateTime = new \DateTime(); |
1112
|
|
|
if ($timestamp !== null) { |
1113
|
|
|
$dateTime->setTimestamp($timestamp); |
1114
|
|
|
} |
1115
|
|
|
|
1116
|
|
|
return $dateTime; |
1117
|
|
|
} |
1118
|
|
|
} |
1119
|
|
|
|
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:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.