Writer   A
last analyzed

↳ Parent: Project

Coupling/Cohesion

Components 1
Dependencies 2

Complexity

Total Complexity 21

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
dl 0
loc 229
ccs 53
cts 53
cp 1
rs 10
c 3
b 0
f 0
wmc 21
lcom 1
cbo 2

11 Methods

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