Test Failed
Push — master ( 31040d...dcbcc7 )
by stéphane
05:35
created

DumperHandlers::dumpCompound()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 7.0178

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 7
eloc 15
nc 6
nop 2
dl 0
loc 21
ccs 13
cts 14
cp 0.9286
crap 7.0178
rs 8.8333
c 2
b 0
f 0
1
<?php
2
namespace Dallgoot\Yaml;
3
4
use Dallgoot\Yaml\Dumper;
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 $dumper;
16
17 8
    public function __construct(Dumper $dumper)
18
    {
19 8
        $this->dumper = $dumper;
20 8
    }
21
22
23 4
    public function dumpScalar($dataType):string
24
    {
25 4
        if ($dataType === \INF) return '.inf';
26 4
        if ($dataType === -\INF) return '-.inf';
27 4
        $precision = "%.".$this->dumper->floatPrecision."F";
28 4
        switch (gettype($dataType)) {
29 4
            case 'boolean': return $dataType ? 'true' : 'false';
30 4
            case 'float': //fall through
31 4
            case 'double': return is_nan((double) $dataType) ? '.nan' : sprintf($precision, $dataType);
32
        }
33 3
        return $this->dumpString($dataType);
34
    }
35
36
37 4
    public function dumpCompound($compound, int $indent):string
38
    {
39 4
        if ($this->dumper->_compactMode) {
40 1
            return $this->dumpCompact($compound, $indent);
41
        } else {
42 3
            if (is_array($compound)) {
43 2
                if ($compound[0] instanceof YamlObject) {
44 2
                    return $this->dumper->dumpMultiDoc($compound);
45 2
                }
46 2
                $iterator = new \ArrayIterator($compound);
47
                $keyMask = '-';
48
                $refKeys = range(0, count($compound) - 1);
49 2
                if (array_keys($compound) !== $refKeys) {
50 2
                    $keyMask = '%s:';
51 1
                }
52
                return $this->dumper->iteratorToString($iterator, $keyMask, "\n", $indent);
53
            } elseif (is_object($compound) && !is_callable($compound)) {
54 1
                return $this->dumpObject($compound, $indent);
55
            }
56
        }
57 1
        throw new \Exception("Dumping Callable|Resource is not currently supported", 1);
58
    }
59 1
60 1
    private function dumpObject($object, int $indent):string
61 1
    {
62 1
        if ($object instanceof YamlObject) {
63 1
            return $this->dumper->dumpYamlObject($object);
64 1
        } elseif ($object instanceof Compact) {
65
            return $this->dumpCompact($object, $indent);
66
        } elseif ($object instanceof Tagged) {
67
            return $this->dumpTagged($object, $indent);
68
        } elseif ($object instanceof \DateTime) {
69
            return $object->format($this->dumper::DATE_FORMAT);
70
        } elseif (is_iterable($object)) {
71
            $iterator = $object;
72
        } else {
73
            $iterator = new \ArrayIterator(get_object_vars($object));
74
        }
75
        return $this->dumper->iteratorToString($iterator, '%s:', "\n", $indent);
76
    }
77
78
79
80
    /**
81
     * Dumps a Compact|mixed (representing an array or object) as the single-line format representation.
82
     * All values inside are assumed single-line as well.
83
     * Note: can NOT use JSON_encode because of possible reference calls or definitions as : '&abc 123', '*fre'
84
     * which would be quoted by json_encode
85
     *
86
     * @param mixed   $subject The subject
87
     * @param integer $indent  The indent
88 2
     *
89
     * @return string the string representation (JSON like) of the value
90 2
     */
91 2
    public function dumpCompact($subject, int $indent):string
92 2
    {
93 1
        $structureFormat = '{%s}';
94
        $keyMask = "%s: ";
95 2
        if (!is_array($subject) && !($subject instanceof \ArrayIterator)) {
96 2
            $source = get_object_vars($subject);
97 2
        } else {
98 2
            $max = count($subject);
99 2
            $objectAsArray = is_array($subject) ? $subject : $subject->getArrayCopy();
100 2
            $source = $objectAsArray;
101
            if (array_keys($objectAsArray) === range(0, $max - 1)) {
102
                $structureFormat = '[%s]';
103 2
                $keyMask = '';
104 2
            }
105 2
        }
106 2
        $previousCompactMode = $this->dumper->_compactMode;
107 2
        $this->dumper->_compactMode =  true;
108
        $result = $this->dumper->iteratorToString(new \ArrayIterator($source), $keyMask, ', ', $indent);
109
        $this->dumper->_compactMode = $previousCompactMode;
110
        return sprintf($structureFormat, $result);
111
    }
112
113
    /**
114
     * Dumps a string. Protects it if needed
115
     *
116
     * @param      string  $str    The string
117
     *
118 4
     * @return     string  ( description_of_the_return_value )
119
     * @todo   implements checking and protection function
120
     */
121
    public function dumpString(string $str):string
122
    {
123
        //those characters must be escaped : - : ? { } [ ] # , & * ! > | ' " %
124
        // The “@” (#x40, at) and “`” (#x60, grave accent) are reserved for future use.
125 4
        // 5.4. Line Break Characters
126 4
        // Example 5.13. Escaped Characters
127
128
        $str = json_encode(ltrim($str));
129 2
        return strspn(substr($str,1,-1), "-:?{}[]#,&*!>|'\"%") > 0 ? $str : trim($str, '"');
130
    }
131 2
132 2
    public function dumpTagged(Tagged $obj, int $indent):string
133 2
    {
134 1
        $separator   = ' ';
135 1
        $valueIndent = 0;
136
        if (!is_scalar($obj->value) && !$this->dumper->_compactMode) {
137 2
            $separator = "\n";
138
            $valueIndent = $indent + $this->dumper::INDENT;
139
        }
140
        return $obj->tagName.$separator.$this->dumper->dump($obj->value, $valueIndent);
141
    }
142
}
143