Completed
Push — master ( e32eeb...714cda )
by
unknown
89:50 queued 46:29
created

OwnerTree::buildTree()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 14

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 29
rs 8.439
cc 6
eloc 14
nc 6
nop 0
1
<?php
2
3
namespace Oro\Bundle\SecurityBundle\Owner;
4
5
/**
6
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
7
 * This class represents a tree of owners
8
 */
9
class OwnerTree implements OwnerTreeInterface
10
{
11
    /**
12
     * An associative array to store owning organization of an user
13
     * key = userId
14
     * value = organizationId
15
     *
16
     * @var array
17
     */
18
    protected $userOwningOrganizationId;
19
20
    /**
21
     * An associative array to store owning organization of a business unit
22
     * key = businessUnitId
23
     * value = organizationId
24
     *
25
     * @var array
26
     */
27
    protected $businessUnitOwningOrganizationId;
28
29
    /**
30
     * An associative array to store owning business unit of an user
31
     * key = userId
32
     * value = businessUnitId
33
     *
34
     * @var array
35
     */
36
    protected $userOwningBusinessUnitId;
37
38
    /**
39
     * An associative array to store organizations assigned to an user
40
     * key = userId
41
     * value = array of organizationId
42
     *
43
     * @var array
44
     */
45
    protected $userOrganizationIds;
46
47
    /**
48
     * An associative array to store business units assigned to an user
49
     * key = userId
50
     * value = array of businessUnitId
51
     *
52
     * @var array
53
     */
54
    protected $userBusinessUnitIds;
55
56
    /**
57
     * An associative array to store business units assigned to an user through organizations
58
     * key = userId
59
     * value = array:
60
     *      key = organizationId
61
     *      value = array of businessUnitIds
62
     *
63
     * @var array
64
     */
65
    protected $userOrganizationBusinessUnitIds;
66
67
    /**
68
     * An associative array to store subordinate business units
69
     * key = businessUnitId
70
     * value = array of businessUnitId
71
     *
72
     * @var array
73
     */
74
    protected $subordinateBusinessUnitIds;
75
76
    /**
77
     * An associative array to store users belong to a business unit
78
     * key = businessUnitId
79
     * value = array of userId
80
     *
81
     * @var array
82
     */
83
    protected $businessUnitUserIds;
84
85
    /**
86
     * An associative array to store users belong to a assigned business unit
87
     * key = businessUnitId
88
     * value = array of userId
89
     *
90
     * @var array
91
     */
92
    protected $assignedBusinessUnitUserIds;
93
94
    /**
95
     * An associative array to store business units belong to an organization
96
     * key = organizationId
97
     * value = array of businessUnitId
98
     *
99
     * @var array
100
     */
101
    protected $organizationBusinessUnitIds;
102
103
    /**
104
     * An associative array to store users belong to an organization
105
     * key = organizationId
106
     * value = array of userId
107
     *
108
     * @var array
109
     */
110
    protected $organizationUserIds;
111
112
    public function __construct()
113
    {
114
        $this->clear();
115
    }
116
117
    /**
118
     * The __set_state handler
119
     *
120
     * @param array $data Initialization array
121
     * @return OwnerTree A new instance of a OwnerTree object
122
     */
123
    // @codingStandardsIgnoreStart
124
    public static function __set_state($data)
125
    {
126
        $result = new OwnerTree();
127
        foreach ($data as $key => $val) {
128
            $result->{$key} = $val;
129
        }
130
131
        return $result;
132
    }
133
    // @codingStandardsIgnoreEnd
134
135
    /**
136
     * Gets the owning organization id for the given user id
137
     *
138
     * @param  int|string $userId
139
     * @return int|string|null
140
     */
141
    public function getUserOrganizationId($userId)
142
    {
143
        return isset($this->userOwningOrganizationId[$userId])
144
            ? $this->userOwningOrganizationId[$userId]
145
            : null;
146
    }
147
148
    /**
149
     * Gets all organization ids assigned to the given user id
150
     *
151
     * @param  int|string $userId
152
     * @return int|string|null
153
     */
154
    public function getUserOrganizationIds($userId)
155
    {
156
        return isset($this->userOrganizationIds[$userId])
157
            ? $this->userOrganizationIds[$userId]
158
            : [];
159
    }
160
161
    /**
162
     * Gets the owning business unit id for the given user id
163
     *
164
     * @param  int|string $userId
165
     * @return int|string|null
166
     */
167
    public function getUserBusinessUnitId($userId)
168
    {
169
        return isset($this->userOwningBusinessUnitId[$userId])
170
            ? $this->userOwningBusinessUnitId[$userId]
171
            : null;
172
    }
173
174
    /**
175
     * Gets all business unit ids assigned to the given user id
176
     *
177
     * @param  int|string      $userId
178
     * @param  int|string|null $organizationId
179
     * @return array      of int|string
180
     */
181
    public function getUserBusinessUnitIds($userId, $organizationId = null)
182
    {
183
        if ($organizationId) {
184
            return isset($this->userOrganizationBusinessUnitIds[$userId][$organizationId])
185
                ? $this->userOrganizationBusinessUnitIds[$userId][$organizationId]
186
                : [];
187
        }
188
189
        return isset($this->userBusinessUnitIds[$userId])
190
            ? $this->userBusinessUnitIds[$userId]
191
            : [];
192
    }
193
194
    /**
195
     * Gets all users ids for the given business unit id
196
     *
197
     * @param  int|string $businessUnitId
198
     * @return array      of int|string
199
     */
200
    public function getBusinessUnitUserIds($businessUnitId)
201
    {
202
        return isset($this->businessUnitUserIds[$businessUnitId])
203
            ? $this->businessUnitUserIds[$businessUnitId]
204
            : [];
205
    }
206
207
    /**
208
     * Gets the owning organization id for the given business unit id
209
     *
210
     * @param  int|string $businessUnitId
211
     * @return int|string|null
212
     */
213
    public function getBusinessUnitOrganizationId($businessUnitId)
214
    {
215
        return isset($this->businessUnitOwningOrganizationId[$businessUnitId])
216
            ? $this->businessUnitOwningOrganizationId[$businessUnitId]
217
            : null;
218
    }
219
220
    /**
221
     * Gets all business unit ids for the given organization id
222
     *
223
     * @param  int|string $organizationId
224
     * @return array      of int|string
225
     */
226
    public function getOrganizationBusinessUnitIds($organizationId)
227
    {
228
        return isset($this->organizationBusinessUnitIds[$organizationId])
229
            ? $this->organizationBusinessUnitIds[$organizationId]
230
            : [];
231
    }
232
233
    /**
234
     * Gets all user ids for the given organization id
235
     *
236
     * @param  int|string $organizationId
237
     * @return array      of int|string
238
     */
239
    public function getOrganizationUserIds($organizationId)
240
    {
241
        $result = [];
242
        $buIds  = $this->getOrganizationBusinessUnitIds($organizationId);
243
        foreach ($buIds as $buId) {
244
            $userIds = $this->getBusinessUnitUserIds($buId);
245
            if (!empty($userIds)) {
246
                $result = array_merge($result, $userIds);
247
            }
248
        }
249
250
        return $result;
251
    }
252
253
    /**
254
     * Gets all subordinate business unit ids for the given business unit id
255
     *
256
     * @param  int|string $businessUnitId
257
     * @return array      of int|string
258
     */
259
    public function getSubordinateBusinessUnitIds($businessUnitId)
260
    {
261
        return isset($this->subordinateBusinessUnitIds[$businessUnitId])
262
            ? $this->subordinateBusinessUnitIds[$businessUnitId]
263
            : [];
264
    }
265
266
    /**
267
     * Gets all user business unit ids with subordinate business unit ids
268
     *
269
     * @param  int        $userId
270
     * @param  int|string $organizationId
271
     * @return array  of int|string
272
     */
273
    public function getUserSubordinateBusinessUnitIds($userId, $organizationId = null)
274
    {
275
        $buIds       = $this->getUserBusinessUnitIds($userId, $organizationId);
276
        $resultBuIds = array_merge($buIds, []);
277
        foreach ($buIds as $buId) {
278
            $diff = array_diff(
279
                $this->getSubordinateBusinessUnitIds($buId),
280
                $resultBuIds
281
            );
282
            if ($diff) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $diff of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
283
                $resultBuIds = array_merge($resultBuIds, $diff);
284
            }
285
        }
286
287
        return $resultBuIds;
288
    }
289
290
    /**
291
     * Gets all user business unit ids by user organization ids
292
     *
293
     * @param int $userId
294
     * @return array  of int|string
295
     */
296
    public function getBusinessUnitsIdByUserOrganizations($userId)
297
    {
298
        $resultBuIds = [];
299
        $orgIds      = $this->getUserOrganizationIds($userId);
300
        foreach ($orgIds as $orgId) {
0 ignored issues
show
Bug introduced by
The expression $orgIds of type integer|string|null 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...
301
            $buIds = $this->getOrganizationBusinessUnitIds($orgId);
302
            if (!empty($buIds)) {
303
                $resultBuIds = array_merge($resultBuIds, $buIds);
304
            }
305
        }
306
307
        return $resultBuIds;
308
    }
309
310
    /**
311
     * Get all business units in system
312
     *
313
     * @return array
314
     */
315
    public function getAllBusinessUnitIds()
316
    {
317
        $resultBuIds = [];
318
319
        if (is_array($this->organizationBusinessUnitIds) && count($this->organizationBusinessUnitIds)) {
320
            foreach ($this->organizationBusinessUnitIds as $businessUnits) {
321
                $resultBuIds = array_merge($resultBuIds, $businessUnits);
322
            }
323
        }
324
325
        return $resultBuIds;
326
    }
327
328
    /**
329
     * Add the given business unit to the tree
330
     *
331
     * @param int|string      $businessUnitId
332
     * @param int|string|null $owningOrganizationId
333
     *
334
     * @deprecated 1.8.0:2.1.0 use OwnerTree::addLocalEntity method
335
     */
336
    public function addBusinessUnit($businessUnitId, $owningOrganizationId)
337
    {
338
        $this->addLocalEntity($businessUnitId, $owningOrganizationId);
339
    }
340
341
    /**
342
     * {@inheritdoc}
343
     */
344
    public function addLocalEntity($localLevelEntityId, $globalLevelEntityId = null)
345
    {
346
        $this->businessUnitOwningOrganizationId[$localLevelEntityId] = $globalLevelEntityId;
347
348
        if ($globalLevelEntityId !== null) {
349
            if (!isset($this->organizationBusinessUnitIds[$globalLevelEntityId])) {
350
                $this->organizationBusinessUnitIds[$globalLevelEntityId] = [];
351
            }
352
            $this->organizationBusinessUnitIds[$globalLevelEntityId][] = $localLevelEntityId;
353
        }
354
355
        $this->businessUnitUserIds[$localLevelEntityId] = [];
356
        foreach ($this->userOwningBusinessUnitId as $userId => $buId) {
357
            if ($localLevelEntityId === $buId) {
358
                $this->businessUnitUserIds[$localLevelEntityId][] = $userId;
359
                $this->userOwningOrganizationId[$userId]          = $globalLevelEntityId;
360
            }
361
        }
362
    }
363
364
    /**
365
     * Add a business unit relation to the tree
366
     *
367
     * @param int|string      $businessUnitId
368
     * @param int|string|null $parentBusinessUnitId
369
     *
370
     * @deprecated 1.8.0:2.1.0 use OwnerTree::addDeepEntity method
371
     */
372
    public function addBusinessUnitRelation($businessUnitId, $parentBusinessUnitId)
373
    {
374
        $this->addDeepEntity($businessUnitId, $parentBusinessUnitId);
375
    }
376
377
    /**
378
     * {@inheritdoc}
379
     */
380
    public function addDeepEntity($localLevelEntityId, $deepLevelEntityId)
381
    {
382
        if ($deepLevelEntityId !== null) {
383
            $this->subordinateBusinessUnitIds[$deepLevelEntityId][] = $localLevelEntityId;
384
        }
385
386
        if (!isset($this->subordinateBusinessUnitIds[$localLevelEntityId])) {
387
            $this->subordinateBusinessUnitIds[$localLevelEntityId] = [];
388
        }
389
    }
390
391
    /**
392
     * {@inheritdoc}
393
     */
394
    public function buildTree()
395
    {
396
        $subordinateBusinessUnitIds = $this->subordinateBusinessUnitIds;
397
        
398
        foreach ($subordinateBusinessUnitIds as $key => $deepLevelEntityIds) {
399
            if (!empty($deepLevelEntityIds)) {
400
                /**
401
                 * We have to add some element to the end of array and remove it after processing,
402
                 * otherwise the last element of the original array will not be processed.
403
                 */
404
                $copy = new \ArrayIterator($deepLevelEntityIds);
405
                foreach ($copy as $position => $deepLevelEntityId) {
406
                    if (!empty($subordinateBusinessUnitIds[$deepLevelEntityId])) {
407
                        $diff = array_diff(
408
                            $subordinateBusinessUnitIds[$deepLevelEntityId],
409
                            $copy->getArrayCopy()
410
                        );
411
                        foreach ($diff as $value) {
412
                            $copy->append($value);
413
                        }
414
                    }
415
                }
416
417
                $subordinateBusinessUnitIds[$key] = $copy->getArrayCopy();
418
            }
419
        }
420
421
        $this->subordinateBusinessUnitIds = $subordinateBusinessUnitIds;
422
    }
423
424
    /**
425
     * Add the given user to the tree
426
     *
427
     * @param int|string      $userId
428
     * @param int|string|null $owningBusinessUnitId
429
     *
430
     * @deprecated 1.8.0:2.1.0 use OwnerTree::addBasicEntity method
431
     */
432
    public function addUser($userId, $owningBusinessUnitId)
433
    {
434
        $this->addBasicEntity($userId, $owningBusinessUnitId);
435
    }
436
437
    /**
438
     * {@inheritdoc}
439
     */
440
    public function addBasicEntity($basicLevelEntityId, $localLevelEntityId = null)
441
    {
442
        $this->userOwningBusinessUnitId[$basicLevelEntityId] = $localLevelEntityId;
443
444
        if ($localLevelEntityId !== null) {
445
            if (isset($this->businessUnitUserIds[$localLevelEntityId])) {
446
                $this->businessUnitUserIds[$localLevelEntityId][] = $basicLevelEntityId;
447
            }
448
449
            $this->userOrganizationIds[$basicLevelEntityId] = [];
450
            if (isset($this->businessUnitOwningOrganizationId[$localLevelEntityId])) {
451
                $this->userOwningOrganizationId[$basicLevelEntityId] =
452
                    $this->businessUnitOwningOrganizationId[$localLevelEntityId];
453
            } else {
454
                $this->userOwningOrganizationId[$basicLevelEntityId] = null;
455
            }
456
        } else {
457
            $this->userOwningOrganizationId[$basicLevelEntityId] = null;
458
            $this->userOrganizationIds[$basicLevelEntityId]      = [];
459
        }
460
461
        $this->userBusinessUnitIds[$basicLevelEntityId]             = [];
462
        $this->userOrganizationBusinessUnitIds[$basicLevelEntityId] = [];
463
    }
464
465
    /**
466
     * @param $buId
467
     * @return array
468
     */
469
    public function getUsersAssignedToBU($buId)
470
    {
471
        return isset($this->assignedBusinessUnitUserIds[$buId])
472
            ? $this->assignedBusinessUnitUserIds[$buId]
473
            : [];
474
    }
475
476
    /**
477
     * Add a business unit to the given user
478
     *
479
     * @param  int|string      $userId
480
     * @param  int|string|null $organizationId
481
     * @param  int|string      $businessUnitId
482
     * @throws \LogicException
483
     *
484
     * @deprecated 1.8.0:2.1.0 use OwnerTree::addLocalEntityToBasic method
485
     */
486
    public function addUserBusinessUnit($userId, $organizationId, $businessUnitId)
487
    {
488
        $this->addLocalEntityToBasic($userId, $businessUnitId, $organizationId);
489
    }
490
491
    /**
492
     * Pay attention that now local level entity is second and global entity is third
493
     *
494
     * {@inheritdoc}
495
     */
496
    public function addLocalEntityToBasic($basicLevelEntityId, $localLevelEntityId, $globalLevelEntityId)
497
    {
498
        if (!isset($this->userOrganizationBusinessUnitIds[$basicLevelEntityId])
499
            || !isset($this->userBusinessUnitIds[$basicLevelEntityId])
500
        ) {
501
            throw new \LogicException(
502
                sprintf('First call OwnerTreeInterface::addBasicEntity for userId: %s.', (string) $basicLevelEntityId)
503
            );
504
        }
505
        if ($localLevelEntityId !== null) {
506
            if (!isset($this->assignedBusinessUnitUserIds[$localLevelEntityId])) {
507
                $this->assignedBusinessUnitUserIds[$localLevelEntityId] = [];
508
            }
509
            $this->assignedBusinessUnitUserIds[$localLevelEntityId][] = $basicLevelEntityId;
510
            $this->userBusinessUnitIds[$basicLevelEntityId][]         = $localLevelEntityId;
511
            if (!isset($this->userOrganizationBusinessUnitIds[$basicLevelEntityId][$globalLevelEntityId])) {
512
                $this->userOrganizationBusinessUnitIds[$basicLevelEntityId][$globalLevelEntityId] = [];
513
            }
514
            $this->userOrganizationBusinessUnitIds[$basicLevelEntityId][$globalLevelEntityId][] = $localLevelEntityId;
515
        }
516
    }
517
518
    /**
519
     * Add a organization to the given user
520
     *
521
     * @param int|string $userId
522
     * @param int|string $organizationId
523
     *
524
     * @deprecated 1.8.0:2.1.0 use OwnerTree::addGlobalEntity method
525
     */
526
    public function addUserOrganization($userId, $organizationId)
527
    {
528
        $this->addGlobalEntity($userId, $organizationId);
529
    }
530
531
    /**
532
     * {@inheritdoc}
533
     */
534
    public function addGlobalEntity($basicLevelEntityId, $globalLevelEntityId)
535
    {
536
        $this->userOrganizationIds[$basicLevelEntityId][] = $globalLevelEntityId;
537
    }
538
539
    /**
540
     * Removes all elements from the tree
541
     */
542
    public function clear()
543
    {
544
        $this->userOwningOrganizationId         = [];
545
        $this->businessUnitOwningOrganizationId = [];
546
        $this->organizationBusinessUnitIds      = [];
547
        $this->userOwningBusinessUnitId         = [];
548
        $this->subordinateBusinessUnitIds       = [];
549
        $this->userOrganizationIds              = [];
550
        $this->userBusinessUnitIds              = [];
551
        $this->businessUnitUserIds              = [];
552
        $this->userOrganizationBusinessUnitIds  = [];
553
        $this->assignedBusinessUnitUserIds      = [];
554
    }
555
}
556