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

DumperHandlers::dumpYamlObject()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 5
nc 4
nop 1
dl 0
loc 12
ccs 0
cts 6
cp 0
crap 30
rs 9.6111
c 0
b 0
f 0
1
<?php
2
namespace Dallgoot\Yaml;
3
4
// use \SplDoublyLinkedList as DLL;
5
6
/**
7
 *  Convert PHP datatypes to a YAML string syntax
8
 *
9
 * @author  Stéphane Rebai <[email protected]>
10
 * @license Apache 2.0
11
 * @link    https://github.com/dallgoot/yaml
12
 */
13
class DumperHandlers
14
{
15
    private const INDENT = 2;
16
    private const OPTIONS = 00000;
17
    private const DATE_FORMAT = 'Y-m-d';
18
19
    private $options;
20
    private $multipleDocs = false;
21
    //options
22
    public const EXPAND_SHORT = 00001;
23
    public const SERIALIZE_CUSTOM_OBJECTS = 00010;
24
    public $floatPrecision = 4;
25
26
    public function __construct(int $options = null)
27
    {
28
        if (is_int($options)) $this->options = $options;
29
    }
30
31
32
33
    public function dump($dataType, int $indent):string
34
    {
35
        if(is_null($dataType)) {
36
            return '';
37
        } elseif(is_resource($dataType)) {
38
            return get_resource_type($dataType);
39
        } elseif (is_scalar($dataType)) {
40
            return $this->dumpScalar($dataType, $indent);
41
        } else {
42
            return $this->dumpCompound($dataType, $indent);
43
        }
44
    }
45
46
    public function dumpScalar($dataType, $indent):string
0 ignored issues
show
Unused Code introduced by
The parameter $indent is not used and could be removed. ( Ignorable by Annotation )

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

46
    public function dumpScalar($dataType, /** @scrutinizer ignore-unused */ $indent):string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
47
    {
48
        if ($dataType === \INF) return '.inf';
49
        if ($dataType === -\INF) return '-.inf';
50
        $precision = "%.".$this->floatPrecision."F";
51
        switch (gettype($dataType)) {
52
            case 'boolean': return $dataType ? 'true' : 'false';
53
            case 'float': //fall through
54
            case 'double': return is_nan((double) $dataType) ? '.nan' : sprintf($precision, $dataType);
55
        }
56
        return $this->dumpString($dataType);
57
    }
58
59
60
    private function dumpCompound($compound, int $indent):string
61
    {
62
        //var_dump(__METHOD__);
63
        $iterator = null;
64
        $mask = '%s:';
65
        if (is_callable($compound)) {
66
            throw new \Exception("Dumping Callable|Closure is not currently supported", 1);
67
        } elseif ($compound instanceof YamlObject) {
68
            //var_dump("YAMLOBJECT");
69
            return $this->dumpYamlObject($compound);
70
        } elseif ($compound instanceof Compact) {
71
             return $this->dumpCompact($compound, $indent);
72
        } elseif (is_array($compound)) {
73
            //var_dump("ARRAY");
74
            $iterator = new \ArrayIterator($compound);
75
            $mask = '-';
76
            $refKeys = range(0, count($compound)-1);
77
            // var_dump("newarray",array_keys($compound), $refKeys);
78
            if (array_keys($compound) !== $refKeys) {
79
                $mask = '%s:';
80
            }
81
        } elseif (is_iterable($compound)) {
82
            //var_dump("ITERABLE");
83
            $iterator = $compound;
84
            // $mask = '%s:';
85
        } elseif (is_object($compound)) {
86
            //var_dump("SPECIAL");
87
            if ($compound instanceof Tagged)     return $this->dumpTagged($compound, $indent);
88
            //TODO:  consider dumping datetime as date strings according to a format provided by user
89
            if ($compound instanceof \DateTime)  return $compound->format(self::DATE_FORMAT);
90
            // $iterator = new \ArrayIterator($compound);
91
            $iterator = new \ArrayIterator(get_object_vars($compound));
92
        }
93
        return $this->iteratorToString($iterator, $mask, $indent);
94
    }
95
96
97
    private function dumpYamlObject(YamlObject $obj):string
98
    {
99
        if ($this->multipleDocs || $obj->hasDocStart() || $obj->isTagged()) {
0 ignored issues
show
Bug introduced by
The method isTagged() does not exist on Dallgoot\Yaml\YamlObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

99
        if ($this->multipleDocs || $obj->hasDocStart() || $obj->/** @scrutinizer ignore-call */ isTagged()) {
Loading history...
100
           $this->multipleDocs = true;
101
          // && $this->$result instanceof DLL) $this->$result->push("---");
102
        }
103
        if (count($obj) > 0) {
104
            //var_dump("indices");
105
            return $this->iteratorToString($obj, '-', 0);
106
        }
107
        //var_dump("no indices");
108
        return $this->iteratorToString(new \ArrayIterator(get_object_vars($obj)), '%s:', 0);
109
        // $this->insertComments($obj->getComment());
110
        //TODO: $references = $obj->getAllReferences();
111
    }
112
113
114
    private function iteratorToString(\Iterator $iterable, string $keyMask, int $indent, bool $isCompact=false):string
0 ignored issues
show
Unused Code introduced by
The parameter $isCompact is not used and could be removed. ( Ignorable by Annotation )

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

114
    private function iteratorToString(\Iterator $iterable, string $keyMask, int $indent, /** @scrutinizer ignore-unused */ bool $isCompact=false):string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
115
    {
116
        $pairs = [];
117
        foreach ($iterable as $key => $value) {
118
            $separator = "\n";
119
            $valueIndent = $indent + self::INDENT;
120
            if (is_scalar($value) || $value instanceof Compact || $value instanceof \DateTime ) {
121
                $separator   = ' ';
122
                $valueIndent = 0;
123
            }
124
            $pairs[] = str_repeat(' ', $indent).sprintf($keyMask, $key).$separator.$this->dump($value, $valueIndent);
125
            //var_dump(str_repeat(' ', $indent)."key($keyMask):$key");
126
        }
127
        //var_dump($pairs);
128
        return implode("\n", $pairs);
129
    }
130
131
    /**
132
     * Dumps a Compact|mixed (representing an array or object) as the single-line format representation.
133
     * All values inside are assumed single-line as well.
134
     * Note: can NOT use JSON_encode because of possible reference calls or definitions as : '&abc 123', '*fre'
135
     * which would be quoted by json_encode
136
     *
137
     * @param mixed   $subject The subject
138
     * @param integer $indent  The indent
139
     *
140
     * @return string the string representation (JSON like) of the value
141
     */
142
    public function dumpCompact($subject, int $indent):string
143
    {
144
        $pairs = [];
145
        if (is_array($subject) || $subject instanceof \ArrayIterator) {
146
            $max = count($subject);
147
            $objectAsArray = is_array($subject) ? $subject : $subject->getArrayCopy();
148
            if(array_keys($objectAsArray) !== range(0, $max-1)) {
149
                $pairs = $objectAsArray;
150
            } else {
151
                $valuesList = [];
152
                foreach ($objectAsArray as $value) {
153
                    $valuesList[] = is_scalar($value) ? $this->dump($value, $indent) : $this->dumpCompact($value, $indent);
154
                }
155
                return '['.implode(', ', $valuesList).']';
156
            }
157
        } else {
158
            $pairs = get_object_vars($subject);
159
        }
160
        $content = [];
161
        foreach ($pairs as $key => $value) {
162
            $content[] = "$key: ".(is_scalar($value) ? $this->dump($value, $indent) : $this->dumpCompact($value, $indent));
163
        }
164
        return '{'.implode(', ', $content).'}';
165
    }
166
167
    /**
168
     * Dumps a string. Protects it if needed
169
     *
170
     * @param      string  $str    The string
171
     *
172
     * @return     string  ( description_of_the_return_value )
173
     * @todo   implements checking and protection function
174
     */
175
    public function dumpString(string $str):string
176
    {
177
        return $str;
178
    }
179
180
    public function dumpTagged(Tagged $obj, int $indent):string
181
    {
182
        $separator   = ' ';
183
        $valueIndent = 0;
184
        if (is_scalar($obj->value)) {
185
            $separator = "\n";
186
            $valueIndent = $indent + self::INDENT;
187
        }
188
        return "!".$obj->tagName.$separator.$this->dump($obj->value, $valueIndent);
189
    }
190
}
191