Completed
Push — master ( 2b7f2d...31c8a2 )
by stéphane
03:00
created

Builder::buildDirective()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
namespace Dallgoot\Yaml;
4
5
use Dallgoot\Yaml\Yaml as Y;
6
7
/**
8
 * Constructs the result (YamlObject or array) according to every Node and respecting value
9
 * @category tag in class comment
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
Coding Style introduced by
Category name "tag in class comment" is not valid; consider "Tag_In_Class_Comment" instead
Loading history...
10
 * @package tag in class comment
1 ignored issue
show
Coding Style introduced by
Package name "tag in class comment" is not valid; consider "Tag_In_Class_Comment" instead
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
11
 * @author tag in class comment
1 ignored issue
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 3 spaces but found 1
Loading history...
12
 * @license tag in class comment
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
13
 */
0 ignored issues
show
Coding Style introduced by
Missing @link tag in class comment
Loading history...
14
final class Builder
15
{
16
    private static $_root;
17
    private static $_debug;
18
19
    const ERROR_NO_KEYNAME = self::class.": key has NO IDENTIFIER on line %d";
20
    const INVALID_DOCUMENT = self::class.": DOCUMENT %d can NOT be a mapping AND a sequence";
21
22
23
    private static function build(object $node, &$parent = null)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
24
    {
25
        if ($node instanceof NodeList) return self::buildNodeList($node, $parent);
26
        return self::buildNode($node, $parent);
27
    }
28
29
    private static function buildNodeList(NodeList $node, &$parent)
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildNodeList" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
30
    {
31
        if ($node->type & (Y::RAW | Y::LITTERALS)) {
32
            return self::buildLitteral($node, $node->type);
0 ignored issues
show
Bug introduced by
It seems like $node->type can also be of type null; however, parameter $type of Dallgoot\Yaml\Builder::buildLitteral() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

32
            return self::buildLitteral($node, /** @scrutinizer ignore-type */ $node->type);
Loading history...
33
        }
34
        $p = $parent;
35
        switch ($node->type) {
36
            case Y::MAPPING: //fall through
37
            case Y::SET:      $p = new \StdClass; break;
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
38
            case Y::SEQUENCE: $p = []; break;
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
39
            // case Y::KEY: $p = $parent;break;
40
        }
41
        $out = null;
42
        foreach ($node as $child) {
43
            $result = self::build($child, $p);
44
            if (!is_null($result)) {
45
                if (is_string($result)) {
46
                    $out .= $result.' ';
47
                } else {
48
                    return $result;
49
                }
50
            }
51
        }
52
        return is_null($out) ? $p : rtrim($out);
53
    }
54
55
    private static function buildNode(Node $node, &$parent)
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildNode" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
56
    {
57
        extract((array) $node, EXTR_REFS);
58
        if ($type & (Y::REF_DEF | Y::REF_CALL)) {
59
            if (is_object($value)) {
60
                $tmp = self::build($value, $parent) ?? $parent;
61
            } else {
62
                $tmp = $node->getPhpValue();
63
            }
64
            if ($type === Y::REF_DEF) self::$_root->addReference($identifier, $tmp);
65
            return self::$_root->getReference($identifier);
66
        }
67
        $typesActions = [Y::COMMENT   => 'buildComment',
68
                         Y::DIRECTIVE => 'buildDirective',
69
                         Y::ITEM      => 'buildItem',
70
                         Y::KEY       => 'buildKey',
71
                         Y::SET_KEY   => 'buildSetKey',
72
                         Y::SET_VALUE => 'buildSetValue',
73
                         Y::TAG       => 'buildTag',
74
        ];
75
        if (isset($typesActions[$type])) {
76
            return self::{$typesActions[$type]}($node, $parent);
77
        }
78
        return is_object($value) ? self::build($value, $parent) : $node->getPhpValue();
79
    }
80
81
    /**
82
     * Builds a key and set the property + value to the given parent
83
     *
84
     * @param Node $node       The node
2 ignored issues
show
Coding Style introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter name; 7 found
Loading history...
85
     * @param object|array $parent       The parent
1 ignored issue
show
Coding Style introduced by
Expected 1 spaces after parameter name; 7 found
Loading history...
86
     *
87
     * @throws \ParseError if Key has no name(identifier)
88
     * @return null
89
     */
90
    private static function buildKey(Node $node, &$parent):void
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildKey" must be prefixed with an underscore
Loading history...
91
    {
92
        extract((array) $node, EXTR_REFS);
93
        if (is_null($identifier)) {
94
            throw new \ParseError(sprintf(self::ERROR_NO_KEYNAME, $line));
95
        } else {
96
            if ($value instanceof Node && ($value->type & (Y::KEY|Y::ITEM))) {
97
                $parent->{$identifier} = $value->type & Y::KEY ? new \StdClass : [];
98
                self::build($value, $parent->{$identifier});
99
            } elseif (is_object($value)) {
100
                $parent->{$identifier} = self::build($value, $parent->{$identifier});
101
            } else {
102
                $parent->{$identifier} = $node->getPhpValue();
103
            }
104
        }
105
    }
106
107
    private static function buildItem(Node $node, &$parent):void
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildItem" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
108
    {
109
        if (!is_array($parent) && !($parent instanceof \ArrayIterator)) {
110
            throw new \Exception("parent must be an Iterable not ".(is_object($parent) ? get_class($parent) : gettype($parent)), 1);
111
        }
112
        if ($value instanceof Node && $value->type === Y::KEY) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $value seems to be never defined.
Loading history...
113
            $parent[$node->value->identifier] = self::build($node->value->value, $parent[$node->value->identifier]);
0 ignored issues
show
Bug introduced by
The property value does not seem to exist on Dallgoot\Yaml\NodeList.
Loading history...
Bug introduced by
It seems like $node->value->value can also be of type null and string; however, parameter $node of Dallgoot\Yaml\Builder::build() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

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

113
            $parent[$node->value->identifier] = self::build(/** @scrutinizer ignore-type */ $node->value->value, $parent[$node->value->identifier]);
Loading history...
Bug introduced by
The property identifier does not seem to exist on Dallgoot\Yaml\NodeList.
Loading history...
114
        } else {
115
            $index = count($parent);
116
            $parent[$index] = self::build($node->value, $parent[$index]);
117
        }
118
    }
119
120
    /**
121
     * Builds a file.  check multiple documents & split if more than one documents
122
     *
123
     * @param   Node   $_root      The root node
3 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter type; 3 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 6 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
124
     * @param   int   $_debug      the level of debugging requested
3 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 3 found
Loading history...
Coding Style introduced by
Expected 1 spaces after parameter name; 6 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
125
     *
126
     * @return array|YamlObject      list of documents or juste one.
127
     */
128
    public static function buildContent(Node $_root, int $_debug)
129
    {
130
        self::$_debug = $_debug;
131
        $totalDocStart = 0;
132
        $documents = [];
133
        if ($_root->value instanceof Node) {
134
            $q = new NodeList;
135
            $q->push($_root->value);
136
            return self::buildDocument($q, 0);
137
        }
138
        $_root->value->setIteratorMode(NodeList::IT_MODE_DELETE);
0 ignored issues
show
Bug introduced by
The method setIteratorMode() does not exist on null. ( Ignorable by Annotation )

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

138
        $_root->value->/** @scrutinizer ignore-call */ 
139
                       setIteratorMode(NodeList::IT_MODE_DELETE);

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...
139
        foreach ($_root->value as $child) {
140
            if ($child->type & Y::DOC_START) $totalDocStart++;
141
            //if 0 or 1 DOC_START = we are still in first document
142
            $currentDoc = $totalDocStart > 1 ? $totalDocStart - 1 : 0;
143
            if (!isset($documents[$currentDoc])) $documents[$currentDoc] = new NodeList();
144
            $documents[$currentDoc]->push($child);
145
        }
146
        $content = array_map([self::class, 'buildDocument'], $documents, array_keys($documents));
147
        return count($content) === 1 ? $content[0] : $content;
148
    }
149
150
    private static function buildDocument(NodeList $list, int $key):YamlObject
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildDocument" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
151
    {
152
        self::$_root = new YamlObject();
153
        $childTypes = $list->getTypes();
154
        $isaMapping  = (bool) (Y::KEY | Y::MAPPING) & $childTypes;
155
        $isaSequence = (bool) Y::ITEM & $childTypes;
156
        $isaSet      = (bool) Y::SET_VALUE & $childTypes;
157
        if ($isaMapping && $isaSequence) {
158
            throw new \ParseError(sprintf(self::INVALID_DOCUMENT, $key));
159
        } else {
160
            switch (true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $isaSet of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $isaSequence of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
161
                case $isaSequence: $list->type = Y::SEQUENCE;break;
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
162
                case $isaSet:      $list->type = Y::SET;break;
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
163
                default:           $list->type = Y::MAPPING;
164
            }
165
        }
166
        $string = '';
167
        foreach ($list as $child) {
168
            $result = self::build($child, self::$_root);
169
            if (is_string($result)) {
170
                $string .= $result.' ';
171
            }
172
        }
173
        if (!empty($string)) {
174
            self::$_root->setText(rtrim($string));
175
        }
176
        return self::$_root;
177
    }
178
179
    private static function buildLitteral(NodeList $children, int $type):string
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildLitteral" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
180
    {
181
        $lines = [];
182
        $children->rewind();
183
        $refIndent = $children->current()->indent;
184
        foreach ($children as $child) {
185
            if ($child->value instanceof NodeList) {
186
                $lines[] = self::buildLitteral($child->value, $type);
187
            } else {
188
                $prefix = '';
189
                if ($type & Y::LITT_FOLDED && ($child->indent > $refIndent || ($child->type & Y::BLANK))) {
190
                    $prefix = "\n";
191
                }
192
                $lines[] = $prefix.$child->value;
193
            }
194
        }
195
        if ($type & Y::RAW)         return implode('',   $lines);
196
        if ($type & Y::LITT)        return implode("\n", $lines);
197
        if ($type & Y::LITT_FOLDED) return implode(' ',  $lines);
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 197 is false. This is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
198
    }
199
200
    private function buildSetKey(Node $node, $parent):void
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildSetKey" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
201
    {
202
        $key = json_encode(self::build($node->value, $parent), JSON_PARTIAL_OUTPUT_ON_ERROR|JSON_UNESCAPED_SLASHES);
0 ignored issues
show
Bug introduced by
It seems like $node->value can also be of type null and string; however, parameter $node of Dallgoot\Yaml\Builder::build() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

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

202
        $key = json_encode(self::build(/** @scrutinizer ignore-type */ $node->value, $parent), JSON_PARTIAL_OUTPUT_ON_ERROR|JSON_UNESCAPED_SLASHES);
Loading history...
203
        if (empty($key))
204
        throw new \Exception("Cant serialize complex key: ".var_export($node->value, true), 1);
205
        $parent->{$key} = null;
206
    }
207
208
    private function buildSetValue(Node $node, $parent):void
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildSetValue" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
209
    {
210
        $prop = array_keys(get_object_vars($parent));
211
        $key = end($prop);
212
        if ($node->value->type & (Y::ITEM|Y::MAPPING)) {
213
            $p = $node->value->type === Y::ITEM ? [] : new \StdClass;
214
            self::build($node->value, $p);
0 ignored issues
show
Bug introduced by
It seems like $node->value can also be of type null and string; however, parameter $node of Dallgoot\Yaml\Builder::build() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

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

214
            self::build(/** @scrutinizer ignore-type */ $node->value, $p);
Loading history...
215
        } else {
216
            $p = self::build($node->value, $parent->{$key});
217
        }
218
        $parent->{$key} = $p;
219
    }
220
221
    private function buildTag(Node $node, $parent)
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildTag" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
222
    {
223
        if ($parent === self::$_root) {
224
            $parent->addTag($node->identifier);
225
            return;
226
        }
227
        //TODO: have somewhere a list of common tags and their treatment
228
        if (in_array($node->identifier, ['!binary', '!str'])) {
229
            if ($node->value->value instanceof NodeList) $node->value->value->type = Y::RAW;
0 ignored issues
show
Bug introduced by
The property value does not seem to exist on Dallgoot\Yaml\NodeList.
Loading history...
230
            else $node->value->type = Y::RAW;
231
        }
232
        $val = is_null($node->value) ? null : self::build(/** @scrutinizer ignore-type */ $node->value, $node);
2 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
233
        return new Tag($node->identifier, $val);
234
    }
235
236
    private function buildComment(Node $node, $parent):void
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildComment" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
237
    {
238
        self::$_root->addComment($node->line, $node->value);
239
    }
240
241
    private function buildDirective($node, $parent)
0 ignored issues
show
Coding Style introduced by
Private method name "Builder::buildDirective" must be prefixed with an underscore
Loading history...
Coding Style introduced by
Missing function doc comment
Loading history...
242
    {
243
        # TODO : implement
0 ignored issues
show
Coding Style introduced by
Perl-style comments are not allowed. Use "// Comment." or "/* comment */" instead.
Loading history...
244
    }
245
}
246