Passed
Push — master ( 9bf5f8...0872bb )
by stéphane
02:09
created

Builder::pushAndSave()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
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
        if ($_debug === 2) {
32
            print_r($root);
33
            return;
34
        }
35
        self::$_debug = $_debug;
36
        $documents = [];
37
        $buffer = new NodeList();
38
        try {
39
            foreach ($root->value as $child) {
40
                if ($child instanceof NodeDocEnd && $child !== $root->value->top()) {
41
                    self::pushAndSave($child, $buffer, $documents);
42
                } elseif ($child instanceof NodeDocStart && $buffer->count() > 0 && $buffer->hasContent()) {
43
                    self::saveAndPush($child, $buffer, $documents);
44
                } else {
45
                    $buffer->push($child);
46
                }
47
            }
48
            $documents[] = self::buildDocument($buffer, count($documents) +1);
49
        } catch (\Exception|\Error|\ParseError $e) {
50
            throw new \Exception($e->getMessage(), 1, $e);
51
        }
52
        return count($documents) === 1 ? $documents[0] : $documents;
53
    }
54
55
    /**
56
     *  Builds the tree of Node for this document (as NodeList)
57
     *
58
     * @param NodeList $list   the list of nodes that constitutes the current document
59
     * @param int      $docNum the index (starts @ 0) of this document in the whole YAML content provided to self::buildContent
60
     *
61
     * @return YamlObject the YAML document as an object
62
     */
63
    private static function buildDocument(NodeList &$list, int $docNum):YamlObject
64
    {
65
        $yamlObject = new YamlObject;
66
        $rootNode   = new NodeRoot();
67
        $list->setIteratorMode(NodeList::IT_MODE_DELETE);
68
        try {
69
            foreach ($list as $child) {
70
                $rootNode->add($child);
71
            }
72
            if (self::$_debug === 3) {
73
                echo "Document #$docNum\n";
74
                print_r($rootNode);
75
            }
76
            return $rootNode->build($yamlObject);
77
        } catch (\Exception|\Error|\ParseError $e) {
78
            throw new \ParseError(sprintf(self::INVALID_DOCUMENT, $docNum).':'.$e->getMessage(), 2, $e);
79
        }
80
    }
81
82
    /**
83
     * Returns the correct PHP type according to the string value
84
     *
85
     * @param string $v a string value
86
     *
87
     * @return mixed The value with appropriate PHP type
88
     * @throws \Exception if happens in Regex::isDate or Regex::isNumber
89
     */
90
    public static function getScalar(string $v, bool $onlyScalar = false)
91
    {
92
        if (Regex::isDate($v))   return self::$dateAsObject && !$onlyScalar ? date_create($v) : $v;
93
        if (Regex::isNumber($v)) return self::getNumber($v);
94
        $types = ['yes'   => true,
95
                  'no'    => false,
96
                  'true'  => true,
97
                  'false' => false,
98
                  'null'  => null,
99
                  '.inf'  => \INF,
100
                  '-.inf' => -\INF,
101
                  '.nan'  => \NAN
102
        ];
103
        return array_key_exists(strtolower($v), $types) ? $types[strtolower($v)] : $v;
104
    }
105
106
    /**
107
     * Returns the correct PHP type according to the string value
108
     *
109
     * @param string $v a string value
110
     *
111
     * @return int|float   The scalar value with appropriate PHP type
112
     * @todo make sure there 's only ONE dot before cosndering a float
113
     */
114
    private static function getNumber(string $v)
115
    {
116
        if (preg_match(Regex::OCTAL_NUM, $v)) return intval(base_convert($v, 8, 10));
117
        if (preg_match(Regex::HEX_NUM, $v))   return intval(base_convert($v, 16, 10));
118
        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...
119
    }
120
121
    private static function pushAndSave(Node $child, NodeList $buffer, array &$documents)
122
    {
123
        $buffer->push($child);
124
        $documents[] = self::buildDocument($buffer, count($documents) + 1);
125
        $buffer = new NodeList();
0 ignored issues
show
Unused Code introduced by
The assignment to $buffer is dead and can be removed.
Loading history...
126
    }
127
128
    private static function saveAndPush(Node $child, NodeList $buffer, array &$documents)
129
    {
130
        $documents[] = self::buildDocument($buffer, count($documents) + 1);
131
        $buffer = new NodeList($child);
0 ignored issues
show
Unused Code introduced by
The assignment to $buffer is dead and can be removed.
Loading history...
132
    }
133
134
135
}
136