SimpleBag::getLowestLevel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Maketok\DataMigration\Unit;
4
5
class SimpleBag implements UnitBagInterface
6
{
7
    /**
8
     * @var UnitInterface[]
9
     */
10
    protected $units;
11
    /**
12
     * @var array
13
     */
14
    protected $levels = [];
15
    /**
16
     * @var array
17
     */
18
    protected $children = [];
19
    /**
20
     * @var array
21
     */
22
    protected $siblings = [];
23
    /**
24
     * @var bool
25
     */
26
    private $compiled = false;
27
28
    /**
29
     * {@inheritdoc}
30
     */
31 41
    public function getIterator()
32
    {
33 41
        $units = array_values($this->units);
34
        // parent units should go first
35
        usort($units, function (UnitInterface $unit1, UnitInterface $unit2) use ($units) {
36 25
            $parent1 = $unit1->getParent();
37 25
            $parent2 = $unit2->getParent();
38 25
            if ($parent1 && !$parent2) {
39 19
                return 1;
40 13
            } elseif(!$parent1 && $parent2) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after ELSEIF keyword; 0 found
Loading history...
41 6
                return -1;
42
            } else {
43 12
                if ($parent1 == $unit2) {
44 1
                    return 1;
45 11
                } elseif ($parent2 == $unit1) {
46
                    return -1;
47
                }
48
            }
49 11
            $ind1 = array_search($unit1, $units);
50 11
            $ind2 = array_search($unit2, $units);
51 11
            if ($ind1 > $ind2) {
52 7
                return 1;
53 4
            } elseif ($ind1 < $ind2) {
54 4
                return -1;
55
            }
56
            return 0;
57 41
        });
58 41
        return new \ArrayIterator($units);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 15
    public function count()
65
    {
66 15
        return count($this->units);
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 55
    public function add(UnitInterface $unit)
73
    {
74 55
        $this->units[$unit->getCode()] = $unit;
75 55
    }
76
77
    /**
78
     * @param array $units
79
     */
80 15
    public function addSet(array $units)
81
    {
82 15
        foreach ($units as $unit) {
83 15
            $this->add($unit);
84 15
        }
85 15
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90 26
    public function getUnitByCode($code)
91
    {
92 26
        if (isset($this->units[$code])) {
93 26
            return $this->units[$code];
94
        }
95
        return false;
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 41
    public function compileTree()
102
    {
103 41
        if ($this->compiled) {
104 8
            return;
105
        }
106 41
        $this->compileChildren();
107 41
        $this->compileLevels();
108 41
        $this->compileSiblings();
109 41
        $this->compiled = true;
110 41
    }
111
112
    /**
113
     * compile children array
114
     */
115 41
    protected function compileChildren()
116
    {
117 41
        foreach ($this->units as $parent) {
118 41
            foreach ($this->units as $unit) {
119 41
                if (($innerP = $unit->getParent()) && $innerP->getCode() == $parent->getCode()) {
120 29
                    $this->children[$parent->getCode()][] = $unit;
121 29
                }
122 41
            }
123 41
        }
124 41
    }
125
126
    /**
127
     * compile levels array
128
     */
129 41
    protected function compileLevels()
130
    {
131 41
        foreach ($this->units as $unit) {
132 41
            $toCheck = clone $unit;
133 41
            $parentLevel = 1;
134 41
            while (($parent = $toCheck->getParent()) !== null) {
135 29
                $parentLevel++;
136 29
                $toCheck = $parent;
137 29
            }
138 41
            $siblingsLevels = [];
139 41
            $i = 0;
140 41
            $siblings = $toCheck->getSiblings();
141 41
            foreach ($siblings as $siblingUnit) {
142 17
                $siblingsLevels[$i] = 1;
143 17
                while (($parent = $siblingUnit->getParent()) !== null) {
144 10
                    $siblingsLevels[$i]++;
145 10
                    $siblingUnit = $parent;
146 10
                }
147 17
                $i++;
148 41
            }
149 41
            if (count($siblingsLevels)) {
150 17
                $level = max(max($siblingsLevels), $parentLevel);
151 17
            } else {
152 30
                $level = $parentLevel;
153
            }
154 41
            $this->levels[$level][] = $unit->getCode();
155 41
        }
156 41
    }
157
158
    /**
159
     * Compile siblings array
160
     */
161 41
    public function compileSiblings()
162
    {
163 41
        foreach ($this->units as $unit) {
164 41
            $siblings = $unit->getSiblings();
165 41
            if (!empty($siblings)) {
166 17
                $mergedSet = array_merge([$unit->getCode() => $unit], $siblings);
167 17
                if (!in_array($mergedSet, $this->siblings)) {
168 17
                    $this->siblings[] = $mergedSet;
169 17
                }
170 17
            }
171 41
        }
172 41
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 17
    public function isLowest($code)
178
    {
179 17
        return $this->getUnitLevel($code) === $this->getLowestLevel();
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185 22
    public function getChildren($code)
186
    {
187 22
        return isset($this->children[$code]) ? $this->children[$code] : [];
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 24
    public function getLowestLevel()
194
    {
195 24
        return max(max(array_keys($this->levels)), 1);
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 28
    public function getUnitLevel($code)
202
    {
203 28
        foreach ($this->levels as $level => $codes) {
204 25
            if (in_array($code, $codes)) {
205 25
                return $level;
206
            }
207 19
        }
208 3
        return 1;
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214 25
    public function getUnitsFromLevel($level)
215
    {
216 25
        return isset($this->levels[$level]) ? $this->levels[$level] : [];
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222 15
    public function getRelations()
223
    {
224
        // from parent-child
225 15
        $sets =[];
226 15
        foreach ($this->children as $key => $units) {
227 11
            foreach ($units as $child) {
228
                /** @var UnitInterface $child */
229 11
                $sets[] = ['pc' => [$key => $this->getUnitByCode($key), $child->getCode() => $child]];
230 11
            }
231 15
        }
232
        // from siblings
233 15
        $siblingArrays = [];
234 15
        foreach ($this->siblings as $set) {
235 9
            $siblingArrays[] = ['s' => $set];
236 15
        }
237 15
        $sets = array_merge($siblingArrays, $sets);
238
        usort($sets, function ($valueA, $valueB) {
239 6
            $setA = array_pop($valueA);
240 6
            $setB = array_pop($valueB);
241
            $setALevels = array_map(function (UnitInterface $unit) {
242 6
                return $this->getUnitLevel($unit->getCode());
243 6
            }, $setA);
244
            $setBLevels = array_map(function (UnitInterface $unit) {
245 6
                return $this->getUnitLevel($unit->getCode());
246 6
            }, $setB);
247 6
            $averageA = array_sum($setALevels)/count($setALevels);
248 6
            $averageB = array_sum($setBLevels)/count($setBLevels);
249 6
            if ($averageA > $averageB) {
250 5
                return -1;
251 2
            } elseif ($averageB > $averageA) {
252 2
                return 1;
253
            }
254
            $codesA = array_map(function (UnitInterface $unit) {
255 1
                return $unit->getCode();
256 1
            }, $setA);
257 1
            $codesB = array_map(function (UnitInterface $unit) {
258 1
                return $unit->getCode();
259 1
            }, $setB);
260 1
            $codeAGlued = implode($codesA);
261 1
            $codeBGlued = implode($codesB);
262 1
            return strcmp($codeAGlued, $codeBGlued);
263 15
        });
264 15
        return $sets;
265
    }
266
}
267