Passed
Push — master ( f81cc4...5281ab )
by stéphane
04:50
created

Builder::buildContent()   B

Complexity

Conditions 10
Paths 17

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 10

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 24
ccs 17
cts 17
cp 1
rs 7.6666
c 0
b 0
f 0
cc 10
nc 17
nop 2
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
use Dallgoot\Yaml\Nodes\NodeGeneric;
6
use Dallgoot\Yaml\NodeList;
7
use Dallgoot\Yaml\Nodes\Root;
8
use Dallgoot\Yaml\Nodes\DocEnd;
9
use Dallgoot\Yaml\Nodes\DocStart;
10
11
/**
12
 * Constructs the result (YamlObject or array) according to every Nodes and their values
13
 *
14
 * @author  Stéphane Rebai <[email protected]>
15
 * @license Apache 2.0
16
 * @link    https://github.com/dallgoot/yaml
17
 */
18
final class Builder
19
{
20
    /** @var boolean */
21
    public static $dateAsObject = false;
22
23
    private static $_debug;
24
25
    const INVALID_DOCUMENT = "DOCUMENT %d is invalid,";
26
27
    /**
28
     * Builds a file.  check multiple documents & split if more than one documents
29
     *
30
     * @param Root $root  The NodeRoot node
31
     * @param int  $_debug    the level of debugging requested
32
     *
33
     * @return array|YamlObject|null   list of documents or just one.
34
     */
35 2
    public static function buildContent(Root $root, int $_debug = 0)
36
    {
37 2
        if ($_debug === 2) {
38 1
            print_r($root);
39 1
            return null;
40
        }
41 2
        self::$_debug = $_debug;
42 2
        $documents = [];
43 2
        $buffer = new NodeList();
44
        try {
45 2
            foreach ($root->value as $child) {
46 1
                if ($child instanceof DocEnd && $child !== $root->value->top()) {
47 1
                    self::pushAndSave($child, $buffer, $documents);
48 1
                } elseif ($child instanceof DocStart && $buffer->count() > 0 && $buffer->hasContent()) {
49 1
                    self::saveAndPush($child, $buffer, $documents);
50
                } else {
51 1
                    $buffer->push($child);
52
                }
53
            }
54 1
            $documents[] = self::buildDocument($buffer, count($documents) +1);
55 1
        } catch (\Exception|\Error|\ParseError $e) {
56 1
            throw new \Exception($e->getMessage(), 1, $e);
57
        }
58 1
        return count($documents) === 1 ? $documents[0] : $documents;
59
    }
60
61
    /**
62
     *  Builds the tree of Node (NodeList) for this document
63
     *
64
     * @param NodeList $list   the list of nodes that constitutes the current document
65
     * @param int      $docNum the index (starts @ 0) of this document in the whole YAML content provided to self::buildContent
66
     *
67
     * @return YamlObject the YAML document as an object
68
     */
69 6
    public static function buildDocument(NodeList &$list, int $docNum):YamlObject
70
    {
71 6
        $yamlObject = new YamlObject;
72 6
        $rootNode   = new Root();
73 6
        $list->setIteratorMode(NodeList::IT_MODE_DELETE);
74
        try {
75 6
            foreach ($list as $child) {
76 5
                $rootNode->add($child);
77
            }
78 5
            if (self::$_debug === 3) {
79 1
                echo "Document #$docNum\n";
80 1
                print_r($rootNode);
81
            }
82 5
            return $rootNode->build($yamlObject);
83 1
        } catch (\Exception|\Error|\ParseError $e) {
84 1
            throw new \ParseError(sprintf(self::INVALID_DOCUMENT, $docNum).':'.$e->getMessage(), 2, $e);
85
        }
86
    }
87
88
    /**
89
     * Returns the correct PHP type according to the string value
90
     *
91
     * @param string $v a string value
92
     *
93
     * @return mixed The value with appropriate PHP type
94
     * @throws \Exception if it happens in Regex::isDate or Regex::isNumber
95
     * @todo implement date as DateTime Object
96
     */
97 4
    public static function getScalar(string $v, bool $onlyScalar = false)
98
    {
99
        /*
100
         10.3.2. Tag Resolution
101
102
The core schema tag resolution is an extension of the JSON schema tag resolution.
103
104
All nodes with the “!” non-specific tag are resolved, by the standard convention, to “tag:yaml.org,2002:seq”, “tag:yaml.org,2002:map”, or “tag:yaml.org,2002:str”, according to their kind.
105
106
Collections with the “?” non-specific tag (that is, untagged collections) are resolved to “tag:yaml.org,2002:seq” or “tag:yaml.org,2002:map” according to their kind.
107
108
Scalars with the “?” non-specific tag (that is, plain scalars) are matched with an extended list of regular expressions. However, in this case, if none of the regular expressions matches, the scalar is resolved to tag:yaml.org,2002:str (that is, considered to be a string).
109
 Regular expression       Resolved to tag
110
 null | Null | NULL | ~      tag:yaml.org,2002:null
111
 Empty      tag:yaml.org,2002:null
112
 true | True | TRUE | false | False | FALSE      tag:yaml.org,2002:bool
113
 [-+]? [0-9]+    tag:yaml.org,2002:int (Base 10)
114
 0o [0-7]+   tag:yaml.org,2002:int (Base 8)
115
 0x [0-9a-fA-F]+     tag:yaml.org,2002:int (Base 16)
116
 [-+]? ( \. [0-9]+ | [0-9]+ ( \. [0-9]* )? ) ( [eE] [-+]? [0-9]+ )?      tag:yaml.org,2002:float (Number)
117
 [-+]? ( \.inf | \.Inf | \.INF )     tag:yaml.org,2002:float (Infinity)
118
 \.nan | \.NaN | \.NAN   tag:yaml.org,2002:float (Not a number)
119
 *   tag:yaml.org,2002:str (Default)
120
 */
121 4
        if (Regex::isDate($v))   return self::$dateAsObject && !$onlyScalar ? date_create($v) : $v;
122 4
        if (Regex::isNumber($v)) return self::getNumber($v);
123 4
        $types = ['yes'   => true,
124
                  'no'    => false,
125
                  'true'  => true,
126
                  'false' => false,
127
                  'null'  => null,
128
                  '.inf'  => \INF,
129
                  '-.inf' => -\INF,
130
                  '.nan'  => \NAN
131
        ];
132 4
        return array_key_exists(strtolower($v), $types) ? $types[strtolower($v)] : $v;
133
    }
134
135
    /**
136
     * Returns the correct PHP type according to the string value
137
     *
138
     * @param string $v a string value
139
     *
140
     * @return int|float   The scalar value with appropriate PHP type
141
     * @todo or scientific notation matching the regular expression -? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?
142
     */
143 1
    private static function getNumber(string $v)
144
    {
145 1
        if ((bool) preg_match(Regex::OCTAL_NUM, $v)) return intval(base_convert($v, 8, 10));
146 1
        if ((bool) preg_match(Regex::HEX_NUM, $v))   return intval(base_convert($v, 16, 10));
147 1
        return is_bool(strpos($v, '.')) || substr_count($v, '.') > 1 ? intval($v) : floatval($v);
148
    }
149
150 2
    public static function pushAndSave(NodeGeneric $child, NodeList &$buffer, array &$documents)
151
    {
152 2
        $buffer->push($child);
153 2
        $documents[] = self::buildDocument($buffer, count($documents) + 1);
154 2
        $buffer = new NodeList();
155 2
    }
156
157 2
    public static function saveAndPush(NodeGeneric $child, NodeList &$buffer, array &$documents)
158
    {
159 2
        $documents[] = self::buildDocument($buffer, count($documents) + 1);
160 2
        $buffer = new NodeList($child);
161 2
    }
162
163
164
}
165