Passed
Push — master ( 844759...f0c5ab )
by stéphane
07:52
created

Builder::buildNodeList()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 10
nc 18
nop 2
dl 0
loc 15
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
/**
6
 * Constructs the result (YamlObject or array) according to every Node and respecting value
7
 *
8
 * @author  Stéphane Rebai <[email protected]>
9
 * @license Apache 2.0
10
 * @link    TODO : url to specific online doc
11
 */
12
final class Builder
13
{
14
    /** @var bool */
15
    public static $dateAsObject = false;
16
17
    private static $_debug;
18
19
    const INVALID_DOCUMENT = "DOCUMENT %d is invalid,";
20
21
    /**
22
     * Builds a file.  check multiple documents & split if more than one documents
23
     *
24
     * @param NodeRoot $root  The root node : Node with Node->type === YAML::ROOT
25
     * @param int  $_debug the level of debugging requested
26
     *
27
     * @return array|YamlObject      list of documents or just one.
28
     */
29
    public static function buildContent(NodeRoot $root, int $_debug)
30
    {
31
        self::$_debug = $_debug;
32
        if ($_debug === 2) {
33
            print_r($root);
34
            return;
35
        }
36
        $documents = [];
37
        $buffer = new NodeList();
38
        try {
39
            foreach ($root->value as $child) {
40
                if ($child instanceof NodeDocEnd && $child !== $root->value->top()) {
0 ignored issues
show
Bug introduced by
The method top() does not exist on Dallgoot\Yaml\Node. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

40
                if ($child instanceof NodeDocEnd && $child !== $root->value->/** @scrutinizer ignore-call */ top()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
41
                    $buffer->push($child);
42
                    $documents[] = self::buildDocument($buffer, count($documents));
43
                    $buffer = new NodeList();
44
                    continue;
45
                } elseif ($child instanceof NodeDocStart && $buffer->count() > 0 && $buffer->hasContent()) {
46
                    $documents[] = self::buildDocument($buffer, count($documents));
47
                    $buffer = new NodeList($child);
48
                    continue;
49
                }
50
                $buffer->push($child);
51
            }
52
            $documents[] = self::buildDocument($buffer, count($documents));
53
        } catch (\Exception|\Error|\ParseError $e) {
54
            throw new \Exception($e->getMessage(), 1, $e);
55
        }
56
        return count($documents) === 1 ? $documents[0] : $documents;
57
    }
58
59
    /**
60
     *  Builds the tree of Node for this document (as NodeList)
61
     *
62
     * @param NodeList $list   the list of nodes that constitutes the current document
63
     * @param int      $docNum the index (starts @ 0) of this document in the whole YAML content provided to self::buildContent
64
     *
65
     * @return YamlObject the YAML document as an object
66
     */
67
    private static function buildDocument(NodeList &$list, int $docNum):YamlObject
68
    {
69
        $yamlObject = new YamlObject;
70
        $rootNode = new NodeRoot();
71
        $list->setIteratorMode(NodeList::IT_MODE_DELETE);
72
        try {
73
            foreach ($list as $child) {
74
                $rootNode->add($child);
75
            }
76
            $out = $rootNode->build($yamlObject);
77
        } catch (\Exception|\Error|\ParseError $e) {
78
            throw new \ParseError(sprintf(self::INVALID_DOCUMENT, $docNum).':'.$e->getMessage(), 2, $e);
79
        }
80
        return $out;
81
    }
82
83
    /**
84
     * Returns the correct PHP type according to the string value
85
     *
86
     * @param string $v a string value
87
     *
88
     * @return mixed The value with appropriate PHP type
89
     * @throws \Exception if happens in Regex::isDate or Regex::isNumber
90
     */
91
    public static function getScalar(string $v, bool $onlyScalar = false)
92
    {
93
        if (Regex::isDate($v))   return self::$dateAsObject && !$onlyScalar ? date_create($v) : $v;
94
        if (Regex::isNumber($v)) return self::getNumber($v);
95
        $types = ['yes'   => true,
96
                    'no'    => false,
97
                    'true'  => true,
98
                    'false' => false,
99
                    'null'  => null,
100
                    '.inf'  => INF,
101
                    '-.inf' => -INF,
102
                    '.nan'  => NAN
103
        ];
104
        return array_key_exists(strtolower($v), $types) ? $types[strtolower($v)] : $v;
105
    }
106
107
    /**
108
     * Returns the correct PHP type according to the string value
109
     *
110
     * @param string $v a string value
111
     *
112
     * @return int|float   The scalar value with appropriate PHP type
113
     * @todo make sure there 's only ONE dot before cosndering a float
114
     */
115
    private static function getNumber(string $v)
116
    {
117
        if (preg_match(Regex::OCTAL_NUM, $v)) return intval(base_convert($v, 8, 10));
118
        if (preg_match(Regex::HEX_NUM, $v))   return intval(base_convert($v, 16, 10));
119
        return is_bool(strpos($v, '.')) ? intval($v) : floatval($v);
0 ignored issues
show
introduced by
The condition is_bool(strpos($v, '.')) is always false.
Loading history...
120
    }
121
122
}
123