Completed
Pull Request — master (#210)
by ignace nyamagana
06:26
created

Writer::initCsv()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
crap 6
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 Traversable;
18
19
/**
20
 * A class to manage data insertion into a CSV
21
 *
22
 * @package League.csv
23
 * @since   4.0.0
24
 * @author  Ignace Nyamagana Butera <[email protected]>
25
 *
26
 */
27
class Writer extends AbstractCsv
28
{
29
    /**
30
     * @inheritdoc
31
     */
32
    protected $stream_filter_mode = STREAM_FILTER_WRITE;
33
34
    /**
35
     * callable collection to validate the record before insertion
36
     *
37
     * @var callable[]
38
     */
39
    protected $validators = [];
40
41
    /**
42
     * callable collection to format the record before insertion
43
     *
44
     * @var callable[]
45
     */
46
    protected $formatters = [];
47
48
    /**
49
     * Insert Rows count
50
     *
51
     * @var int
52
     */
53
    protected $insert_count = 0;
54
55
    /**
56
     * newline character
57
     *
58
     * @var string
59
     */
60
    protected $newline = "\n";
61
62
    /**
63
     * Buffer flush threshold
64
     *
65
     * @var int
66
     */
67
    protected $flush_threshold = 500;
68
69
    /**
70
     * Returns the current newline sequence characters
71
     *
72
     * @return string
73
     */
74 4
    public function getNewline(): string
75
    {
76 4
        return $this->newline;
77
    }
78
79
    /**
80
     * Get the flush threshold
81
     *
82
     * @return int|null
83
     */
84 2
    public function getFlushThreshold()
85
    {
86 2
        return $this->flush_threshold;
87
    }
88
89
    /**
90
     * Adds multiple lines to the CSV document
91
     *
92
     * a simple wrapper method around insertOne
93
     *
94
     * @param Traversable|array $rows a multidimensional array or a Traversable object
95
     *
96
     * @throws InvalidArgumentException If the given rows format is invalid
97
     *
98
     * @return int
99
     */
100 6
    public function insertAll($rows): int
101
    {
102 6
        if (!is_array($rows) && !$rows instanceof Traversable) {
103 2
            throw new InvalidArgumentException('the provided data must be an array OR a `Traversable` object');
104
        }
105
106 4
        $bytes = 0;
107 4
        foreach ($rows as $row) {
108 4
            $bytes += $this->insertOne($row);
109
        }
110
111 4
        return $bytes;
112
    }
113
114
    /**
115
     * Adds a single line to a CSV document
116
     *
117
     * @param string[] $row an array
118
     *
119
     * @throws InsertionException If the row can not be inserted
120
     *
121
     * @return int
122
     */
123 32
    public function insertOne(array $row): int
124
    {
125 32
        $record = array_reduce($this->formatters, [$this, 'formatRecord'], $row);
126 32
        $this->validateRecord($record);
127 28
        $bytes = $this->document->fputcsv($record, $this->delimiter, $this->enclosure, $this->escape);
128 28
        if (!$bytes) {
129 2
            throw InsertionException::createFromCsv($record);
130
        }
131
132 26
        return $bytes + $this->consolidate();
133
    }
134
135
    /**
136
     * Format the given row
137
     *
138
     * @param string[] $record
139
     * @param callable $formatter
140
     *
141
     * @return string[]
142
     */
143 4
    protected function formatRecord(array $record, callable $formatter): array
144
    {
145 4
        return $formatter($record);
146
    }
147
148
    /**
149
     * Validate a row
150
     *
151
     * @param string[] $record
152
     *
153
     * @throws InsertionException If the validation failed
154
     */
155 32
    protected function validateRecord(array $record)
156
    {
157 32
        foreach ($this->validators as $name => $validator) {
158 8
            if (true !== ($validator)($record)) {
159 8
                throw InsertionException::createFromValidator($name, $record);
160
            }
161
        }
162 28
    }
163
164
    /**
165
     * Apply post insertion actions
166
     *
167
     * @return int
168
     */
169 26
    protected function consolidate(): int
170
    {
171 26
        $bytes = 0;
172 26
        if ("\n" !== $this->newline) {
173 4
            $this->document->fseek(-1, SEEK_CUR);
174 4
            $bytes = $this->document->fwrite($this->newline, strlen($this->newline)) - 1;
175
        }
176
177 26
        $this->insert_count++;
178 26
        if (null !== $this->flush_threshold && 0 === $this->insert_count % $this->flush_threshold) {
179 2
            $this->document->fflush();
180
        }
181
182 26
        return $bytes;
183
    }
184
185
    /**
186
     * add a formatter to the collection
187
     *
188
     * @param callable $formatter
189
     *
190
     * @return static
191
     */
192 4
    public function addFormatter(callable $formatter): self
193
    {
194 4
        $this->formatters[] = $formatter;
195
196 4
        return $this;
197
    }
198
199
    /**
200
     * add a Validator to the collection
201
     *
202
     * @param callable $validator
203
     * @param string   $name      the validator name
204
     *
205
     * @return static
206
     */
207 8
    public function addValidator(callable $validator, string $name): self
208
    {
209 8
        $this->validators[$name] = $validator;
210
211 8
        return $this;
212
    }
213
214
    /**
215
     * Sets the newline sequence characters
216
     *
217
     * @param string $newline
218
     *
219
     * @return static
220
     */
221 4
    public function setNewline(string $newline): self
222
    {
223 4
        $this->newline = (string) $newline;
224
225 4
        return $this;
226
    }
227
228
    /**
229
     * Set the automatic flush threshold on write
230
     *
231
     * @param int|null $val
232
     */
233 4
    public function setFlushThreshold($val): self
234
    {
235 4
        if (null !== $val) {
236 4
            $val = $this->filterInteger($val, 1, 'The flush threshold must be a valid positive integer or null');
237
        }
238
239 4
        $this->flush_threshold = $val;
240
241 4
        return $this;
242
    }
243
}
244