Test Failed
Push — master ( fc4f20...ea5a85 )
by stéphane
13:54
created

DumperHandlers::dumpString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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