Completed
Pull Request — master (#348)
by
unknown
13:49
created

XMLConverter::import()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 16
ccs 4
cts 4
cp 1
crap 3
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * League.Csv (https://csv.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace League\Csv;
15
16
use DOMAttr;
17
use DOMDocument;
18
use DOMElement;
19
use DOMException;
20
use Traversable;
21
use TypeError;
22
use function gettype;
23
use function is_iterable;
24
use function sprintf;
25
26
/**
27
 * Converts tabular data into a DOMDOcument object.
28
 */
29
class XMLConverter
30
{
31
    /**
32
     * XML Root name.
33
     *
34
     * @var string
35
     */
36
    protected $root_name = 'csv';
37
38
    /**
39
     * XML Node name.
40
     *
41
     * @var string
42
     */
43
    protected $record_name = 'row';
44
45
    /**
46
     * XML Item name.
47
     *
48
     * @var string
49
     */
50
    protected $field_name = 'cell';
51
52
    /**
53
     * XML column attribute name.
54
     *
55
     * @var string
56
     */
57
    protected $column_attr = '';
58
59
    /**
60
     * XML offset attribute name.
61
     *
62
     * @var string
63
     */
64
    protected $offset_attr = '';
65
66
    /**
67
     * Conversion method list.
68
     *
69
     * @var array
70
     */
71
    protected $encoder = [
72
        'field' => [
73
            true => 'fieldToElementWithAttribute',
74
            false => 'fieldToElement',
75
        ],
76
        'record' => [
77
            true => 'recordToElementWithAttribute',
78
            false => 'recordToElement',
79
        ],
80
    ];
81
82
    /**
83
     * Convert a Record collection into a DOMDocument.
84
     *
85
     * @param array|Traversable $records the CSV records collection
86
     *
87 6
     * @return DOMDocument
88
     */
89 6
    public function convert($records): DOMDocument
90 3
    {
91
        $doc = new DOMDocument('1.0');
92
        $doc->appendChild(
93 3
            $this->import($records, $doc)
0 ignored issues
show
Documentation introduced by
$records is of type array|object<Traversable>, but the function expects a object<League\Csv\iterable>.

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...
94 3
        );
95 3
        return $doc;
96 3
    }
97 3
98 3
    /**
99 3
     * Create a new DOMElement related to the given DOMDocument.
100
     *
101 3
     * **DOES NOT** attach to the DOMDocument
102
     *
103 3
     * @param iterable $records
104
     *
105
     * @return DOMElement
106
     */
107
    public function import($records, DOMDocument $doc): DOMElement
108
    {
109
        if (!is_iterable($records)) {
110 3
            throw new TypeError(sprintf('%s() expects argument passed to be iterable, %s given', __METHOD__, gettype($records)));
111
        }
112
113
        $field_encoder = $this->encoder['field']['' !== $this->column_attr];
114
        $record_encoder = $this->encoder['record']['' !== $this->offset_attr];
115
        $root = $doc->createElement($this->root_name);
116 3
        foreach ($records as $offset => $record) {
117 3
            $node = $this->$record_encoder($doc, $record, $field_encoder, $offset);
118
            $root->appendChild($node);
119 3
        }
120
121
        return $root;
122
    }
123
124
    /**
125 3
     * Convert a CSV record into a DOMElement and
126
     * adds its offset as DOMElement attribute.
127 3
     */
128 3
    protected function recordToElementWithAttribute(
129 3
        DOMDocument $doc,
130 3
        array $record,
131
        string $field_encoder,
132
        int $offset
133 3
    ): DOMElement {
134
        $node = $this->recordToElement($doc, $record, $field_encoder);
135
        $node->setAttribute($this->offset_attr, (string) $offset);
136
137
        return $node;
138
    }
139
140
    /**
141
     * Convert a CSV record into a DOMElement.
142
     */
143
    protected function recordToElement(DOMDocument $doc, array $record, string $field_encoder): DOMElement
144 3
    {
145
        $node = $doc->createElement($this->record_name);
146 3
        foreach ($record as $node_name => $value) {
147 3
            $item = $this->$field_encoder($doc, (string) $value, $node_name);
148
            $node->appendChild($item);
149 3
        }
150
151
        return $node;
152
    }
153
154
    /**
155
     * Convert Cell to Item.
156
     *
157 3
     * Convert the CSV item into a DOMElement and adds the item offset
158
     * as attribute to the returned DOMElement
159 3
     *
160 3
     * @param int|string $node_name
161
     */
162 3
    protected function fieldToElementWithAttribute(DOMDocument $doc, string $value, $node_name): DOMElement
163
    {
164
        $item = $this->fieldToElement($doc, $value);
165
        $item->setAttribute($this->column_attr, (string) $node_name);
166
167
        return $item;
168 6
    }
169
170 6
    /**
171 6
     * Convert Cell to Item.
172
     *
173 3
     * @param string $value Record item value
174
     */
175
    protected function fieldToElement(DOMDocument $doc, string $value): DOMElement
176
    {
177
        $item = $doc->createElement($this->field_name);
178
        $item->appendChild($doc->createTextNode($value));
179
180
        return $item;
181 6
    }
182
183 6
    /**
184
     * XML root element setter.
185
     */
186
    public function rootElement(string $node_name): self
187
    {
188
        $clone = clone $this;
189 3
        $clone->root_name = $this->filterElementName($node_name);
190
191 3
        return $clone;
192 3
    }
193 3
194
    /**
195 3
     * Filter XML element name.
196
     *
197
     * @throws DOMException If the Element name is invalid
198
     */
199
    protected function filterElementName(string $value): string
200
    {
201
        return (new DOMElement($value))->tagName;
202
    }
203
204
    /**
205 6
     * XML Record element setter.
206
     */
207 6
    public function recordElement(string $node_name, string $record_offset_attribute_name = ''): self
208 3
    {
209
        $clone = clone $this;
210
        $clone->record_name = $this->filterElementName($node_name);
211 3
        $clone->offset_attr = $this->filterAttributeName($record_offset_attribute_name);
212
213
        return $clone;
214
    }
215
216
    /**
217 3
     * Filter XML attribute name.
218
     *
219 3
     * @param string $value Element name
220 3
     *
221 3
     * @throws DOMException If the Element attribute name is invalid
222
     */
223 3
    protected function filterAttributeName(string $value): string
224
    {
225
        if ('' === $value) {
226
            return $value;
227
        }
228
229
        return (new DOMAttr($value))->name;
230
    }
231
232
    /**
233
     * XML Field element setter.
234
     */
235
    public function fieldElement(string $node_name, string $fieldname_attribute_name = ''): self
236
    {
237
        $clone = clone $this;
238
        $clone->field_name = $this->filterElementName($node_name);
239
        $clone->column_attr = $this->filterAttributeName($fieldname_attribute_name);
240
241
        return $clone;
242
    }
243
}
244