SequentialOrderTrait   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 12
lcom 0
cbo 1
dl 0
loc 100
ccs 0
cts 41
cp 0
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
C insertSequential() 0 49 8
A ensureSequential() 0 11 4
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipboxfactory/craft-sortable-associations/blob/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/craft-sortable-associations
7
 */
8
9
namespace flipbox\craft\sortable\associations\services\traits;
10
11
use craft\helpers\ArrayHelper;
12
13
/**
14
 * @author Flipbox Factory <[email protected]>
15
 * @since 1.0.1
16
 */
17
trait SequentialOrderTrait
18
{
19
    /**
20
     * @param array $sourceArray The source array which the target is to be inserted into.  The
21
     * key represents a unique identifier, while the value is the sort order.
22
     *
23
     * As an example if this is the $sourceArray
24
     *
25
     * ```
26
     * [
27
     *      111 => 1,
28
     *      343 => 2,
29
     *      545 => 3,
30
     *      'foo' => 4,
31
     *      'bar' => 5
32
     * ]
33
     * ```
34
     *
35
     * And your $targetKey is 'fooBar' with a $targetOrder of 4, the result would be
36
     *
37
     * ```
38
     * [
39
     *      111 => 1,
40
     *      343 => 2,
41
     *      545 => 3,
42
     *      'fooBar' => 4,
43
     *      'foo' => 5,
44
     *      'bar' => 6
45
     * ]
46
     * ```
47
     *
48
     * @param string|int $targetKey
49
     * @param int $targetOrder
50
     * @return array|bool
51
     */
52
    protected function insertSequential(array $sourceArray, $targetKey, int $targetOrder)
53
    {
54
        $this->ensureSequential($sourceArray);
55
56
        // Append exiting types after position
57
        if (false === ($indexPosition = array_search($targetKey, array_keys($sourceArray)))) {
58
            return false;
59
        }
60
61
        // Determine the furthest affected index
62
        $affectedIndex = $indexPosition >= $targetOrder ? ($targetOrder - 1) : $indexPosition;
63
64
        // All that are affected by re-ordering
65
        $affectedTypes = array_slice($sourceArray, $affectedIndex, null, true);
66
67
        // Remove the current (we're going to put it back in later)
68
        $currentPosition = (int)ArrayHelper::remove($affectedTypes, $targetKey);
69
70
        // Already in that position?
71
        if ($currentPosition === $targetOrder) {
72
            return true;
73
        }
74
75
        $startingSortOrder = $targetOrder;
76
        if ($affectedIndex++ < $targetOrder) {
77
            $startingSortOrder = $affectedIndex;
78
        }
79
80
        // Prepend current type
81
        $order = [$targetKey => $targetOrder];
82
83
        // Assemble order
84
        if (false !== ($position = array_search($targetOrder, array_values($affectedTypes)))) {
85
            if ($indexPosition < $targetOrder) {
86
                $position++;
87
            }
88
89
            if ($position > 0) {
90
                $order = array_slice($affectedTypes, 0, $position, true) + $order;
91
            }
92
93
            $order += array_slice($affectedTypes, $position, null, true);
94
        }
95
96
        return array_flip(array_combine(
97
            range($startingSortOrder, count($order)),
98
            array_keys($order)
99
        ));
100
    }
101
102
    /**
103
     * @param array $sourceArray
104
     */
105
    private function ensureSequential(array &$sourceArray)
106
    {
107
        $ct = 1;
108
        foreach ($sourceArray as $key => &$sortOrder) {
109
            $sortOrder = (int) $sortOrder ?: $ct++;
110
111
            if ($sortOrder > $ct) {
112
                $ct = $sortOrder + 1;
113
            }
114
        }
115
    }
116
}
117