Passed
Branch master (09b7c0)
by stéphane
02:52
created

DumperHandlers::dumpCompound()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.0163

Importance

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