Passed
Pull Request — master (#62)
by Alexander
07:46
created

SaveOrder::beforeMerge()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Arrays\Collection\Modifier;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Arrays\Collection\Modifier\ModifierInterface\AfterMergeModifierInterface;
9
use Yiisoft\Arrays\Collection\Modifier\ModifierInterface\BeforeMergeModifierInterface;
10
11
use function is_array;
12
use function is_int;
13
use function is_string;
14
15
/**
16
 * Remembers the order of elements in the collection it is applied to
17
 * and tried to keep the order while merging.
18
 *
19
 * Usage only with merge. For example:
20
 *
21
 * ```php
22
 * $a = [
23
 *     'name' => 'Yii',
24
 *     'options' => [
25
 *         'count' => 42,
26
 *         'description' => null,
27
 *     ],
28
 *     'version' => '1.1',
29
 *     'meta' => ['date' => '19.11.2013'],
30
 * ];
31
 * $b = new ArrayCollection(
32
 *     [
33
 *         'version' => '3.0',
34
 *         'options' => [
35
 *             'count' => 97,
36
 *             'use' => true,
37
 *         ],
38
 *     ],
39
 *     new SaveOrder()
40
 * );
41
 *
42
 * // [
43
 * //     'version' => '3.0',
44
 * //     'options' => [
45
 * //         'count' => 97,
46
 * //         'description' => null,
47
 * //         'use' => true,
48
 * //     ],
49
 * //     'name' => 'Yii',
50
 * //     'meta' => ['date' => '19.11.2013'],
51
 * // ],
52
 * $result = ArrayHelper::merge($a, $b);
53
 * ```
54
 */
55
final class SaveOrder extends Modifier implements BeforeMergeModifierInterface, AfterMergeModifierInterface
56
{
57
    private array $array = [];
58
59
    private bool $nested = false;
60
61
    /**
62
     * Save order for nested arrays and collections.
63
     *
64
     * @return self
65
     */
66 2
    public function nested(): self
67
    {
68 2
        $new = clone $this;
69 2
        $new->nested = true;
70 2
        return $new;
71
    }
72
73
    /**
74
     * Save order only for top level of collection (default).
75
     *
76
     * @return self
77
     */
78 1
    public function notNested(): self
79
    {
80 1
        $new = clone $this;
81 1
        $new->nested = false;
82 1
        return $new;
83
    }
84
85 5
    public function beforeMerge(array $arrays, int $index): array
86
    {
87 5
        $this->array = $arrays[$index];
88 5
        return $this->array;
89
    }
90
91 5
    public function afterMerge(array $data): array
92
    {
93 5
        return $this->applyOrder($data, $this->array);
94
    }
95
96 5
    private function applyOrder(array $data, array $array): array
97
    {
98 5
        $result = [];
99
100 5
        foreach ($array as $key => $value) {
101 5
            if (is_string($key)) {
102 4
                if (array_key_exists($key, $data)) {
103 4
                    $result[$key] = ArrayHelper::remove($data, $key);
104
                }
105
            } else {
106 1
                foreach ($data as $dataKey => $dataValue) {
107 1
                    if (is_int($dataKey) && $dataValue === $value) {
108 1
                        $result[] = $dataValue;
109 1
                        unset($data[$dataKey]);
110 1
                        break;
111
                    }
112
                }
113
            }
114
115 5
            if ($this->nested && is_array($value) && is_array($result[$key])) {
116 2
                $result[$key] = $this->applyOrder($result[$key], $value);
117
            }
118
        }
119
120 5
        return array_merge($result, $data);
121
    }
122
}
123