buildFromTraversableLike()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * Incoming
4
 *
5
 * @author    Trevor Suarez (Rican7)
6
 * @copyright (c) Trevor Suarez
7
 * @link      https://github.com/Rican7/incoming
8
 * @license   MIT
9
 */
10
11
declare(strict_types=1);
12
13
namespace Incoming\Structure;
14
15
use ArrayIterator;
16
use Incoming\Structure\Exception\InvalidStructuralTypeException;
17
use Traversable;
18
19
/**
20
 * A default implementation of the `StructureFactory` for building the included
21
 * structural types from loose input data.
22
 */
23
class RecursiveInputStructureFactory implements StructureFactory
24
{
25
26
    /**
27
     * Build a structure from a loose-type.
28
     *
29
     * @param mixed $data The input data.
30
     * @return Structure The resulting data-structure.
31
     */
32 60
    public function build($data): Structure
33
    {
34 60
        return static::buildFromTraversableLike($data);
35
    }
36
37
    /**
38
     * Build a structure from "Traversable-like" data.
39
     *
40
     * This allows to build from data that is either an array or Traversable, as
41
     * PHP's array type works JUST like a Traversable instance but doesn't
42
     * actually implement any interfaces.
43
     *
44
     * @param Traversable|array $data The input data.
45
     * @throws InvalidStructuralTypeException If the data type isn't supported.
46
     * @return Structure The built structure.
47
     */
48 60
    protected static function buildFromTraversableLike($data): Structure
49
    {
50 60
        if (is_array($data)) {
51 51
            return static::buildFromArray($data);
52 12
        } elseif ($data instanceof Traversable) {
0 ignored issues
show
introduced by
$data is always a sub-type of Traversable.
Loading history...
53 9
            return static::buildFromTraversable($data);
54
        }
55
56 3
        throw InvalidStructuralTypeException::withTypeInfo($data);
57
    }
58
59
    /**
60
     * Build a structure from data in an array.
61
     *
62
     * @param array $data The input data.
63
     * @return Structure The built structure.
64
     */
65 51
    protected static function buildFromArray(array $data): Structure
66
    {
67 51
        return static::buildFromTraversable(
68 51
            new ArrayIterator($data)
69
        );
70
    }
71
72
    /**
73
     * Build a structure from data in a Traversable instance.
74
     *
75
     * @param Traversable $data The input data.
76
     * @return Structure The built structure.
77
     */
78 57
    protected static function buildFromTraversable(Traversable $data): Structure
79
    {
80 57
        $is_map = false;
81
82
        // Traverse through the data, but only check the first item's key
83 57
        foreach ($data as $key => &$val) {
84 51
            $is_map = $is_map || !is_int($key);
85
86 51
            $val = self::attemptBuildTraversableLike($val);
87
        }
88
89 57
        if ($is_map) {
90 42
            return Map::fromTraversable($data);
91
        }
92
93 21
        return FixedList::fromTraversable($data);
94
    }
95
96
    /**
97
     * Attempt to build a structure from "Traversable-like" data.
98
     *
99
     * If the data type isn't supported, we simply return the original data
100
     * untouched. This allows to more easily traverse deeply nested structures.
101
     *
102
     * @param mixed $data The input data.
103
     * @return Structure|mixed The built structure or original data.
104
     */
105 51
    private static function attemptBuildTraversableLike($data)
106
    {
107 51
        if (is_array($data) || $data instanceof Traversable) {
108 12
            $data = static::buildFromTraversableLike($data);
109
        }
110
111 51
        return $data;
112
    }
113
}
114