SortOrderHelper::insertSequential()   C
last analyzed

Complexity

Conditions 13
Paths 152

Size

Total Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 0
Metric Value
dl 0
loc 67
ccs 0
cts 43
cp 0
rs 5.6666
c 0
b 0
f 0
cc 13
nc 152
nop 3
crap 182

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
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipboxfactory/craft-ember/blob/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/craft-ember/
7
 */
8
9
namespace flipbox\craft\ember\helpers;
10
11
/**
12
 * @author Flipbox Factory <[email protected]>
13
 * @since 2.0.0
14
 */
15
class SortOrderHelper
16
{
17
    /**
18
     * @param array $sourceArray The source array which the target is to be inserted into.  The
19
     * key represents a unique identifier, while the value is the sort order.
20
     *
21
     * As an example if this is the $sourceArray
22
     *
23
     * ```
24
     * [
25
     *      111 => 1,
26
     *      343 => 2,
27
     *      545 => 3,
28
     *      'foo' => 4,
29
     *      'bar' => 5
30
     * ]
31
     * ```
32
     *
33
     * And your $targetKey is 'fooBar' with a $targetOrder of 4, the result would be
34
     *
35
     * ```
36
     * [
37
     *      111 => 1,
38
     *      343 => 2,
39
     *      545 => 3,
40
     *      'fooBar' => 4,
41
     *      'foo' => 5,
42
     *      'bar' => 6
43
     * ]
44
     * ```
45
     *
46
     * @param string|int $targetKey
47
     * @param int $targetOrder
48
     * @return array|bool
49
     */
50
    public static function insertSequential(array $sourceArray, $targetKey, int $targetOrder)
51
    {
52
        $altered = self::ensureSequential($sourceArray);
53
54
        // Must be greater than 1
55
        $targetOrder = $targetOrder > 0 ? $targetOrder : 1;
56
57
        // Append exiting types after position
58
        if (false === ($indexPosition = array_search($targetKey, array_keys($sourceArray)))) {
59
            return false;
60
        }
61
62
        $affectedIndex = 0;
63
        $affectedTypes = $sourceArray;
64
        if ($altered === false) {
65
            // Determine the furthest affected index
66
            $affectedIndex = $indexPosition >= $targetOrder ? ($targetOrder - 1) : $indexPosition;
67
68
            // All that are affected by re-ordering
69
            $affectedTypes = array_slice($sourceArray, $affectedIndex, null, true);
70
        }
71
72
        // Remove the current (we're going to put it back in later)
73
        $currentPosition = (int)ArrayHelper::remove($affectedTypes, $targetKey);
74
75
        // Prepend current type
76
        $order = [$targetKey => $targetOrder];
77
78
        // Already in that position?
79
        if ($altered === false && $currentPosition === $targetOrder) {
80
            return true;
81
        }
82
83
        $startingSortOrder = $targetOrder;
84
        if ($affectedIndex++ < $targetOrder) {
85
            $startingSortOrder = $affectedIndex;
86
        }
87
88
        // Assemble order
89
        if (false !== ($position = array_search($targetOrder, array_values($affectedTypes)))) {
90
            if ($indexPosition < $targetOrder) {
91
                $position++;
92
            }
93
        } else {
94
            // Couldn't find a matching position (likely this means it was in the correct position already)
95
96
            if ($indexPosition < $targetOrder) {
97
                $position = $indexPosition;
98
            }
99
100
            // The target order is way beyond our max
101
            if ($targetOrder > count($affectedTypes)) {
102
                $position = count($affectedTypes);
103
            }
104
        }
105
106
        if ($position > 0) {
107
            $order = array_slice($affectedTypes, 0, $position, true) + $order;
108
        }
109
110
        $order += array_slice($affectedTypes, $position, null, true);
111
112
        return array_flip(array_combine(
113
            range($startingSortOrder, count($order)),
114
            array_keys($order)
115
        ));
116
    }
117
118
    /**
119
     *
120
     * @param array $sourceArray
121
     * @return bool
122
     */
123
    private static function ensureSequential(array &$sourceArray): bool
124
    {
125
        $ct = 0;
126
        $altered = false;
127
        foreach ($sourceArray as $key => &$sortOrder) {
128
            $ct++;
129
            $sortOrder = (int)$sortOrder;
130
131
            if ($sortOrder !== $ct) {
132
                $altered = true;
133
                $sortOrder = $ct;
134
            }
135
        }
136
137
        return $altered;
138
    }
139
}
140