HalXmlRenderer::resourcesForXml()   B
last analyzed

Complexity

Conditions 6
Paths 12

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8817
c 0
b 0
f 0
cc 6
nc 12
nop 3
1
<?php
2
/**
3
 * This file is part of the Hal library
4
 *
5
 * (c) Ben Longden <[email protected]
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @package Nocarrier
11
 */
12
namespace Nocarrier;
13
14
/**
15
 * HalXmlRenderer
16
 *
17
 * @uses HalRenderer
18
 * @package Nocarrier
19
 * @author Ben Longden <[email protected]>
20
 */
21
class HalXmlRenderer implements HalRenderer
22
{
23
    /**
24
     * Render.
25
     *
26
     * @param \Nocarrier\Hal $resource
27
     * @param bool $pretty
28
     * @return string
29
     */
30
    public function render(Hal $resource, $pretty, $encode = true)
31
    {
32
        $doc = new \SimpleXMLElement('<resource></resource>');
33
        if (!is_null($resource->getUri())) {
34
            $doc->addAttribute('href', $resource->getUri());
35
        }
36
        $this->linksForXml($doc, $resource->getLinks());
0 ignored issues
show
Documentation introduced by
$resource->getLinks() is of type array, but the function expects a object<Nocarrier\HalLinkContainer>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
37
38
        $this->arrayToXml($resource->getData(), $doc);
39
40
        foreach ($resource->getResources() as $rel => $resources) {
41
            $this->resourcesForXml($doc, $rel, $resources);
42
        }
43
44
        $dom = dom_import_simplexml($doc);
45
        if ($pretty) {
46
            $dom->ownerDocument->preserveWhiteSpace = false;
47
            $dom->ownerDocument->formatOutput = true;
48
        }
49
50
        return $dom->ownerDocument->saveXML();
51
    }
52
53
    /**
54
     * linksForXml
55
     *
56
     * Add links in hal+xml format to a SimpleXmlElement object.
57
     *
58
     * @param \SimpleXmlElement $doc
59
     * @param \Nocarrier\HalLinkContainer $links
60
     * @return void
61
     */
62
    protected function linksForXml(\SimpleXmlElement $doc, HalLinkContainer $links)
63
    {
64
        foreach ($links as $rel => $links) {
65
            foreach ($links as $link) {
66
                $element = $doc->addChild('link');
67
                $element->addAttribute('rel', $rel);
68
                $element->addAttribute('href', $link->getUri());
69
                foreach ($link->getAttributes() as $attribute => $value) {
70
                    $element->addAttribute($attribute, $value);
71
                }
72
            }
73
        }
74
    }
75
76
    /**
77
     * arrayToXml
78
     *
79
     * @param array $data
80
     * @param \SimpleXmlElement $element
81
     * @param mixed $parent
82
     * @access protected
83
     * @return void
84
     */
85
    protected function arrayToXml($data, \SimpleXmlElement $element, $parent = null)
86
    {
87
        foreach ($data as $key => $value) {
88
            if (is_array($value) || $value instanceof \Traversable) {
89
                if (!is_numeric($key)) {
90
                    if (count($value) > 0 && isset($value[0])) {
91
                        $this->arrayToXml($value, $element, $key);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type object<Traversable>; however, Nocarrier\HalXmlRenderer::arrayToXml() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
92
                    } else {
93
                        $subnode = $element->addChild($key);
94
                        $this->arrayToXml($value, $subnode, $key);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type object<Traversable>; however, Nocarrier\HalXmlRenderer::arrayToXml() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
95
                    }
96
                } else {
97
                    $subnode = $element->addChild($parent);
98
                    $this->arrayToXml($value, $subnode, $parent);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type object<Traversable>; however, Nocarrier\HalXmlRenderer::arrayToXml() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
99
                }
100
            } else {
101
                if (!is_numeric($key)) {
102
                    if (substr($key, 0, 1) === '@') {
103
                        $element->addAttribute(substr($key, 1), $value);
104
                    } elseif ($key === 'value' and count($data) === 1) {
105
                        $element[0] = $value;
106
                    } elseif (is_bool($value)) {
107
                        $element->addChild($key, intval($value));
108
                    } else {
109
                        $element->addChild($key, htmlspecialchars($value, ENT_QUOTES));
110
                    }
111
                } else {
112
                    $element->addChild($parent, htmlspecialchars($value, ENT_QUOTES));
113
                }
114
            }
115
        }
116
    }
117
118
    /**
119
     * resourcesForXml
120
     *
121
     * Add resources in hal+xml format (identified by $rel) to a
122
     * SimpleXmlElement object.
123
     *
124
     * @param \SimpleXmlElement $doc
125
     * @param mixed $rel
126
     * @param mixed $resources
127
     */
128
    protected function resourcesForXml(\SimpleXmlElement $doc, $rel, $resources)
129
    {
130
        if (!is_array($resources)) {
131
            $resources = array($resources);
132
        }
133
134
        foreach($resources as $resource) {
135
136
            $element = $doc->addChild('resource');
137
            $element->addAttribute('rel', $rel);
138
139
            if ($resource) {
140
                if (!is_null($resource->getUri())) {
141
                    $element->addAttribute('href', $resource->getUri());
142
                }
143
144
                $this->linksForXml($element, $resource->getLinks());
145
146
                foreach ($resource->getResources() as $innerRel => $innerRes) {
147
                    $this->resourcesForXml($element, $innerRel, $innerRes);
148
                }
149
150
                $this->arrayToXml($resource->getData(), $element);
151
            }
152
        }
153
    }
154
}
155