Writer   A
last analyzed

↳ Parent: Project

Coupling/Cohesion

Components 1
Dependencies 2

Complexity

Total Complexity 21

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

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