Completed
Pull Request — master (#178)
by ignace nyamagana
02:35
created

Header::getHeader()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
/**
3
* This file is part of the League.csv library
4
*
5
* @license http://opensource.org/licenses/MIT
6
* @link https://github.com/thephpleague/csv/
7
* @version 8.1.1
8
* @package League.csv
9
*
10
* For the full copyright and license information, please view the LICENSE
11
* file that was distributed with this source code.
12
*/
13
namespace League\Csv\Config;
14
15
use InvalidArgumentException;
16
use League\Csv\AbstractCsv;
17
use LimitIterator;
18
use SplFileObject;
19
20
/**
21
 * A trait to configure and check CSV header
22
 *
23
 * @package League.csv
24
 * @since  9.0.0
25
 *
26
 */
27
trait Header
28
{
29
    /**
30
     * Csv Header Info
31
     *
32
     * @var array|int
33
     */
34
    protected $header = [];
35
36
    /**
37
     * Returns the inner SplFileObject
38
     *
39
     * @return SplFileObject
40
     */
41
    abstract public function getIterator();
42
43
    /**
44
     * Returns the current field enclosure
45
     *
46
     * @return string
47
     */
48
    abstract public function getEnclosure();
49
50
    /**
51
     * Returns the BOM sequence of the given CSV
52
     *
53
     * @return string
54
     */
55
    abstract public function getInputBOM();
56
57
    /**
58
     * Tell whether to use Stream Filter or not to convert the CSV
59
     *
60
     * @return bool
61
     */
62
    abstract protected function useInternalConverter(AbstractCsv $csv);
63
64
    /**
65
     * Convert a CSV record to UTF-8
66
     *
67
     * @param array  $record
68
     * @param string $input_encoding
69
     *
70
     * @return array
71
     */
72
    abstract protected function convertRecord(array $record, $input_encoding);
73
74
    /**
75
     * Strip the BOM character from the record
76
     *
77
     * @param array  $record
78
     * @param string $bom
79
     * @param string $enclosure
80
     *
81
     * @return array
82
     */
83
    abstract protected function stripBOM(array $record, $bom, $enclosure);
84
85
    /**
86
     * Tell whether the current header is internal
87
     * or user submitted
88
     *
89
     * @return int|null
90
     */
91
    public function getHeaderOffset()
92
    {
93
        if (is_array($this->header)) {
94
            return null;
95
        }
96
97
        return $this->header;
98
    }
99
100
    /**
101
     * Returns the CSV header
102
     *
103
     * @return array
104
     */
105
    public function getHeader()
106
    {
107
        if (is_array($this->header)) {
108
            return $this->header;
109
        }
110
111
        return $this->getHeaderFromDocument();
112
    }
113
114
    /**
115
     * Get the Header from a CSV record
116
     *
117
     * @return array
118
     */
119
    protected function getHeaderFromDocument()
120
    {
121
        $iterator = new LimitIterator($this->getIterator(), $this->header);
122
        $iterator->rewind();
123
        $header = $iterator->current();
124
        if ($iterator->key() !== $this->header) {
125
            throw new InvalidArgumentException('the select offset does not exist');
126
        }
127
128
        if (0 !== $this->header) {
129
            return $header;
130
        }
131
132
        return $this->formatHeader($header, $this->getInputBOM(), $this->getEnclosure());
133
    }
134
135
    /**
136
     * Format the Document Header
137
     *
138
     * @param string[] $header
139
     *
140
     * @return string[]
141
     */
142
    protected function formatHeader(array $header, $bom, $enclosure)
143
    {
144
        $header = $this->stripBOM($header, $bom, $enclosure);
145
        if (!$this->useInternalConverter($this)) {
146
            return $header;
147
        }
148
149
        return $this->convertRecord($header, $this->getInputEncoding());
0 ignored issues
show
Bug introduced by
It seems like getInputEncoding() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
150
    }
151
152
    /**
153
     * Selects the array to be used as key for the fetchAssoc method
154
     *
155
     * @param int|null|array $offset_or_keys the assoc key OR the row Index to be used
156
     *                                       as the key index
157
     *
158
     * @return array
159
     */
160
    public function setHeader($offset_or_keys)
161
    {
162
        if (is_array($offset_or_keys)) {
163
            $this->header = $this->validateHeader($offset_or_keys);
164
            return $this;
165
        }
166
167
        if (null === $offset_or_keys) {
168
            $this->header = [];
169
            return $this;
170
        }
171
172
        $this->header = $this->validateInteger($offset_or_keys, 0, 'the header offset is invalid');
0 ignored issues
show
Bug introduced by
It seems like validateInteger() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
173
        return $this;
174
    }
175
176
    /**
177
     * Validates the array to be used by the fetchAssoc method
178
     *
179
     * @param array $keys
180
     *
181
     * @throws InvalidArgumentException If the submitted array fails the assertion
182
     *
183
     * @return array
184
     */
185
    protected function validateHeader(array $keys)
186
    {
187
        if (empty($keys)) {
188
            return $keys;
189
        }
190
191
        foreach ($keys as &$value) {
192
            $value = $this->validateString($value);
0 ignored issues
show
Bug introduced by
It seems like validateString() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
193
        }
194
        unset($value);
195
196
        if (count(array_unique($keys)) == count($keys)) {
197
            return $keys;
198
        }
199
200
        throw new InvalidArgumentException('Use a flat array with unique string values');
201
    }
202
}
203