These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* |
||
3 | * @author Tom Klingenberg <[email protected]> |
||
4 | */ |
||
5 | |||
6 | namespace N98\Util\Console\Helper\Table\Renderer; |
||
7 | |||
8 | use DOMDocument; |
||
9 | use DOMElement; |
||
10 | use DOMException; |
||
11 | use RuntimeException; |
||
12 | use Symfony\Component\Console\Output\OutputInterface; |
||
13 | |||
14 | /** |
||
15 | * Class XmlRenderer |
||
16 | * |
||
17 | * @package N98\Util\Console\Helper\Table\Renderer |
||
18 | */ |
||
19 | class XmlRenderer implements RendererInterface |
||
20 | { |
||
21 | const NAME_ROOT = 'table'; |
||
22 | const NAME_ROW = 'row'; |
||
23 | |||
24 | private $headers; |
||
25 | |||
26 | /** |
||
27 | * {@inheritdoc} |
||
28 | */ |
||
29 | public function render(OutputInterface $output, array $rows) |
||
30 | { |
||
31 | $dom = new DOMDocument('1.0', 'UTF-8'); |
||
32 | $dom->formatOutput = true; |
||
33 | |||
34 | $rows && $this->setHeadersFrom($rows); |
||
0 ignored issues
–
show
|
|||
35 | |||
36 | $table = $dom->createElement(self::NAME_ROOT); |
||
37 | |||
38 | /** @var DOMElement $table */ |
||
39 | $table = $dom->appendChild($table); |
||
40 | |||
41 | $this->appendHeaders($table, $this->headers); |
||
42 | $this->appendRows($table, $rows); |
||
43 | |||
44 | /** @var $output \Symfony\Component\Console\Output\StreamOutput */ |
||
45 | $output->write($dom->saveXML(), false, $output::OUTPUT_RAW); |
||
46 | } |
||
47 | |||
48 | private function appendRows(DOMElement $parent, array $rows) |
||
49 | { |
||
50 | $doc = $parent->ownerDocument; |
||
51 | |||
52 | if (!$rows) { |
||
0 ignored issues
–
show
The expression
$rows of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
53 | $parent->appendChild($doc->createComment('intentionally left blank, the table is empty')); |
||
54 | |||
55 | return; |
||
56 | } |
||
57 | |||
58 | foreach ($rows as $fields) { |
||
59 | /** @var DOMElement $row */ |
||
60 | $row = $parent->appendChild($doc->createElement(self::NAME_ROW)); |
||
61 | $this->appendRowFields($row, $fields); |
||
62 | } |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * @param DOMElement $row |
||
67 | * @param array $fields |
||
68 | */ |
||
69 | private function appendRowFields(DOMElement $row, array $fields) |
||
70 | { |
||
71 | $index = 0; |
||
72 | foreach ($fields as $key => $value) { |
||
73 | $header = $this->getHeader($index++, $key); |
||
74 | $element = $this->createField($row->ownerDocument, $header, $value); |
||
75 | $row->appendChild($element); |
||
76 | } |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * @param DOMElement $parent |
||
81 | * @param array $headers |
||
82 | */ |
||
83 | private function appendHeaders(DOMElement $parent, array $headers = null) |
||
84 | { |
||
85 | if (!$headers) { |
||
86 | return; |
||
87 | } |
||
88 | |||
89 | $doc = $parent->ownerDocument; |
||
90 | |||
91 | $parent = $parent->appendChild($doc->createElement('headers')); |
||
92 | |||
93 | foreach ($headers as $header) { |
||
94 | $parent->appendChild($doc->createElement('header', $header)); |
||
95 | } |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * create a DOMElement containing the data |
||
100 | * |
||
101 | * @param DOMDocument $doc |
||
102 | * @param string $key |
||
103 | * @param string $value |
||
104 | * |
||
105 | * @return DOMElement |
||
106 | */ |
||
107 | private function createField(DOMDocument $doc, $key, $value) |
||
108 | { |
||
109 | $name = $this->getName($key); |
||
110 | |||
111 | $base64 = !preg_match('//u', $value) || preg_match('/[\x0-\x8\xB-\xC\xE-\x1F]/', $value); |
||
112 | |||
113 | $node = $doc->createElement($name, $base64 ? base64_encode($value) : $value); |
||
114 | |||
115 | if ($base64) { |
||
116 | $node->setAttribute('encoding', 'base64'); |
||
117 | } |
||
118 | |||
119 | return $node; |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * @param string $string |
||
124 | * |
||
125 | * @return string valid XML element name |
||
126 | * |
||
127 | * @throws DOMException if no valid XML Name can be generated |
||
128 | * @throws RuntimeException if character encoding is not US-ASCII or UTF-8 |
||
129 | */ |
||
130 | private function getName($string) |
||
131 | { |
||
132 | $name = preg_replace("/[^a-z0-9]/ui", '_', $string); |
||
133 | if (null === $name) { |
||
134 | throw new RuntimeException( |
||
135 | sprintf('Encoding error, only US-ASCII and UTF-8 supported, can not process %s', var_export($string, true)) |
||
0 ignored issues
–
show
|
|||
136 | ); |
||
137 | } |
||
138 | |||
139 | try { |
||
140 | new DOMElement("$name"); |
||
141 | } catch (DOMException $e) { |
||
142 | throw new DOMException(sprintf('Invalid name %s', var_export($name, true))); |
||
143 | } |
||
144 | |||
145 | return $name; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @param int $index zero-based |
||
150 | * @param mixed $default |
||
151 | * |
||
152 | * @return string |
||
153 | */ |
||
154 | private function getHeader($index, $default = null) |
||
155 | { |
||
156 | if (!isset($this->headers[$index])) { |
||
157 | return $default; |
||
158 | } |
||
159 | |||
160 | return $this->headers[$index]; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * @param array $rows |
||
165 | * |
||
166 | * @return void |
||
167 | */ |
||
168 | private function setHeadersFrom(array $rows) |
||
169 | { |
||
170 | $first = reset($rows); |
||
171 | |||
172 | if (is_array($first)) { |
||
173 | $this->headers = array_keys($first); |
||
174 | } |
||
175 | } |
||
176 | } |
||
177 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.