Completed
Push — master ( 636580...9c56d4 )
by ignace nyamagana
02:35
created

Encoder::filter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 4
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 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 9.0.0
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
declare(strict_types=1);
14
15
namespace League\Csv;
16
17
use Iterator;
18
use php_user_filter;
19
use Traversable;
20
21
/**
22
 *  A class to encode your CSV records collection
23
 *
24
 * @package League.csv
25
 * @since   9.0.0
26
 * @author  Ignace Nyamagana Butera <[email protected]>
27
 */
28
class Encoder extends php_user_filter
29
{
30
    use ValidatorTrait;
31
32
    const FILTER_NAME = 'league.csv.encoder';
33
34
    /**
35
     * The records input encoding charset
36
     *
37
     * @var string
38
     */
39
    protected $input_encoding = 'UTF-8';
40
41
    /**
42
     * The records output encoding charset
43
     *
44
     * @var string
45
     */
46
    protected $output_encoding = 'UTF-8';
47
48
    /**
49
     * Static method to register the class as
50
     * a PHP stream filter
51
     *
52
     * @return bool
53
     */
54 4
    public static function registerStreamFilter(): bool
55
    {
56 4
        return stream_filter_register(self::FILTER_NAME.'.*', Encoder::class);
57
    }
58
59
    /**
60
     * @inherit
61
     */
62 2
    public function filter($in, $out, &$consumed, $closing)
63
    {
64 2
        while ($res = stream_bucket_make_writeable($in)) {
65 2
            $res->data = @mb_convert_encoding($res->data, $this->output_encoding, $this->input_encoding);
66 2
            $consumed += $res->datalen;
67 2
            stream_bucket_append($out, $res);
68
        }
69
70 2
        return PSFS_PASS_ON;
71
    }
72
73
    /**
74
     * @inherit
75
     */
76 4
    public function onCreate()
77
    {
78 4
        $params = substr($this->filtername, strlen(self::FILTER_NAME) + 1);
79 4
        if (!preg_match(',^(?<input>[-\w]+)\/(?<output>[-\w]+)$,', $params, $matches)) {
80 2
            return false;
81
        }
82
83 2
        $this->input_encoding = $this->filterEncoding($matches['input']);
84 2
        $this->output_encoding = $this->filterEncoding($matches['output']);
85 2
        return true;
86
    }
87
88
    /**
89
     * Enable using the class as a formatter for the {@link Writer}
90
     *
91
     * @see encodeOne
92
     *
93
     * @param array $record CSV record
94
     *
95
     * @return string[]
96
     */
97 2
    public function __invoke(array $record): array
98
    {
99 2
        return $this->encodeOne($record);
100
    }
101
102
    /**
103
     * Encode a CSV record
104
     *
105
     * @param array $record CSV record
106
     *
107
     * @return string[]
108
     */
109 2
    public function encodeOne(array $record): array
110
    {
111 2
        if ($this->output_encoding !== $this->input_encoding) {
112 2
            array_walk($record, [$this, 'encodeField']);
113
        }
114
115 2
        return $record;
116
    }
117
118
    /**
119
     * Walker method to convert the offset and the value of a CSV record field
120
     *
121
     * @param string|null &$value
122
     * @param string|int  &$offset
123
     */
124 4
    protected function encodeField(&$value, &$offset)
125
    {
126 4
        if (null !== $value) {
127 4
            $value = mb_convert_encoding((string) $value, $this->output_encoding, $this->input_encoding);
128
        }
129
130 4
        if (!is_int($offset)) {
131 4
            $offset = mb_convert_encoding((string) $offset, $this->output_encoding, $this->input_encoding);
132
        }
133 4
    }
134
135
    /**
136
     * Convert Csv file into UTF-8
137
     *
138
     * @param array|Traversable $records the CSV records collection
139
     *
140
     * @return array|Iterator
141
     */
142 4
    public function encodeAll($records)
143
    {
144 4
        $records = $this->filterIterable($records, __METHOD__);
145 4
        if ($this->output_encoding === $this->input_encoding) {
146 2
            return $records;
147
        }
148
149 2
        $convert = function (array $record): array {
150 2
            array_walk($record, [$this, 'encodeField']);
151 2
            return $record;
152 1
        };
153
154 2
        return is_array($records) ? array_map($convert, $records) : new MapIterator($records, $convert);
155
    }
156
157
    /**
158
     * Sets the records input encoding charset
159
     *
160
     * @param string $encoding
161
     *
162
     * @return static
163
     */
164 6
    public function inputEncoding(string $encoding): self
165
    {
166 6
        $encoding = $this->filterEncoding($encoding);
167 4
        if ($encoding === $this->input_encoding) {
168 2
            return $this;
169
        }
170
171 2
        $clone = clone $this;
172 2
        $clone->input_encoding = $encoding;
173
174 2
        return $clone;
175
    }
176
177
    /**
178
     * Sets the records output encoding charset
179
     *
180
     * @param string $encoding
181
     *
182
     * @return static
183
     */
184 4
    public function outputEncoding(string $encoding): self
185
    {
186 4
        $encoding = $this->filterEncoding($encoding);
187 4
        if ($encoding === $this->output_encoding) {
188 2
            return $this;
189
        }
190
191 4
        $clone = clone $this;
192 4
        $clone->output_encoding = $encoding;
193
194 4
        return $clone;
195
    }
196
}
197