Passed
Push — master ( f8295f...487b9a )
by stéphane
02:46
created

NodeList   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Test Coverage

Coverage 97.47%

Importance

Changes 0
Metric Value
eloc 77
dl 0
loc 158
ccs 77
cts 79
cp 0.9747
rs 9.36
c 0
b 0
f 0
wmc 38

9 Methods

Rating   Name   Duplication   Size   Complexity  
A has() 0 9 3
B hasContent() 0 12 7
A __construct() 0 6 2
A filterComment() 0 20 5
B push() 0 16 7
A checkTypeCoherence() 0 8 1
B buildMultiline() 0 20 7
A buildList() 0 7 2
A build() 0 14 4
1
<?php
2
3
namespace Dallgoot\Yaml;
4
5
use Dallgoot\Yaml\Nodes\NodeGeneric;
6
use Dallgoot\Yaml\Nodes\Blank;
7
use Dallgoot\Yaml\Nodes\Comment;
8
use Dallgoot\Yaml\Nodes\Directive;
9
use Dallgoot\Yaml\Nodes\Docstart;
10
use Dallgoot\Yaml\Nodes\Item;
11
use Dallgoot\Yaml\Nodes\Key;
12
use Dallgoot\Yaml\Nodes\SetKey;
13
use Dallgoot\Yaml\Nodes\SetValue;
14
use Dallgoot\Yaml\Nodes\Scalar;
15
16
17
/**
18
 * A collection of Nodes
19
 *
20
 * @author  Stéphane Rebai <[email protected]>
21
 * @license Apache 2.0
22
 * @link    https://github.com/dallgoot/yaml
23
 */
24
class NodeList extends \SplDoublyLinkedList
25
{
26
    const MAPPING   = 1;
27
    const MULTILINE = 2;
28
    const SEQUENCE  = 4;
29
    const SET       = 8;
30
31
    public $type;
32
33
    /**
34
     * NodeList constructor
35
     *
36
     * @param NodeGeneric|null $node (optional) a node that will be pushed as first element
37
     */
38 10
    public function __construct(NodeGeneric $node = null)
39
    {
40
        // parent::__construct();
41
        // $this->setIteratorMode(self::IT_MODE_KEEP);
42 10
        if (!is_null($node)) {
43 10
            $this->push($node);
44
        }
45 10
    }
46
47 1
    public function has(string $nodeType):bool
48
    {
49 1
        $tmp = clone $this;
50 1
        $tmp->rewind();
51 1
        $fqn = __NAMESPACE__."\\Nodes\\$nodeType";
52 1
        foreach ($tmp as $child) {
53 1
            if ($child instanceof $fqn) return true;
54
        }
55 1
        return false;
56
    }
57
58 2
    public function hasContent():bool
59
    {
60 2
        $tmp = clone $this;
61 2
        $tmp->rewind();
62 2
        foreach ($tmp as $child) {
63 2
            if (!($child instanceof Comment)
64 2
                && !($child instanceof Directive)
65 2
                && !($child instanceof Blank)
66 1
                && !($child instanceof Docstart
67 2
                && is_null($child->value)) ) return true;
68
        }
69 1
        return false;
70
    }
71
72 10
    public function push($node)
73
    {
74 10
        $type = null;
75 10
        if ($node instanceof Item ) {
76 2
            $type = self::SEQUENCE;
77 10
        } elseif ($node instanceof Key) {
78 2
            $type = self::MAPPING;
79 10
        } elseif ($node->isOneOf('SetKey','SetValue')) {
80 1
            $type = self::SET;
81 10
        } elseif ($node instanceof Scalar){
82 3
            $type = self::MULTILINE;
83
        }
84 10
        if (!is_null($type) && $this->checkTypeCoherence($type)) {
85 3
            $this->type = $type;
86
        }
87 10
        parent::push($node);
88 10
    }
89
90
    /**
91
     * Verify that the estimated type is coherent with this list current $type
92
     *
93
     * @param      int      $estimatedType  The estimated type
94
     *
95
     * @return     boolean  True if coherent, False otherwise
96
     * @todo       implement invalid cases
97
     */
98 4
    public function checkTypeCoherence($estimatedType):bool
99
    {
100
       // if ($this->type === self::MAPPING) {
101
       //     if ($estimatedType === self::SEQUENCE) {
102
       //         throw new \ParseError("Error : no coherence in types", 1);
103
       //     }
104
       // }
105 4
       return (bool) $estimatedType;
106
    }
107
108 1
    public function build(&$parent = null)
109
    {
110 1
        switch ($this->type) {
111 1
            case self::MAPPING:  //fall through
112 1
            case self::SET:
113 1
                $collect = $parent ?? new \StdClass;
114 1
                return $this->buildList($collect);
115 1
            case self::SEQUENCE:
116 1
                $collect = $parent ?? [];
117 1
                return $this->buildList($collect);
118
            default:
119 1
                $this->filterComment();
120
                // return Nodes\Scalar::getScalar($this->buildMultiline());
121 1
                return (new Nodes\Scalar('', 0))->getScalar($this->buildMultiline(), true);
122
        }
123
    }
124
125 2
    public function buildList(&$collector)
126
    {
127 2
        $this->rewind();
128 2
        foreach ($this as $child) {
129 2
            $child->build($collector);
130
        }
131 2
        return $collector;
132
    }
133
134 2
    public function buildMultiline():string
135
    {
136 2
        $output = '';
137 2
        $list = clone $this;
138 2
        if ($list->count() > 0) {
139 2
            $list->rewind();
140 2
            $first = $list->shift();
141 2
            $output = trim($first->raw);
142 2
            foreach ($list as $child) {
143 1
                if ($child instanceof Scalar) {
144 1
                    $separator = isset($output[-1])  && $output[-1] === "\n" ? '' : ' ';
145 1
                    $output .= $separator.trim($child->raw);
146 1
                } elseif ($child instanceof Blank) {
147 1
                    $output .= "\n";
148
                } else {
149
                    $child->build();
150
                }
151
            }
152
        }
153 2
        return trim($output);
154
    }
155
156
    /**
157
     * Remove NodeComment and returns a new one
158
     *
159
     * @return   NodeList  a new NodeList without NodeComment in it
160
     * @todo     double check that NodeComment are built
161
     */
162 2
    public function filterComment():NodeList
163
    {
164 2
        $this->rewind();
165 2
        $out = new NodeList;
166 2
        foreach ($this as $index => $child) {
167 2
            if ($child instanceof Comment) {
168
                // $child->build();
169
            } else {
170 2
                if($child->value instanceof Comment) {
171
                    // $child->value->build();
172
                    // $child->value = null;
173 2
                } elseif($child->value instanceof NodeList) {
174
                    $child->value = $child->value->filterComment();
175
                }
176 2
                $out->push($child);
177
            }
178
        }
179
        // $this->rewind();
180 2
        $out->rewind();
181 2
        return $out;
182
    }
183
184
    /**
185
     * Provides a slimmer output when using var_dump Note: currently PHP ignores it on SPL types
186
     * @todo activate when PHP supports it
187
     */
188
    // public function __debugInfo()
189
    // {
190
    //     return ['type'=> Y::getName($this->type), 'dllist'=> $this->dllist];
191
    // }
192
}
193