Completed
Push — master ( ecd0f8...3ad52b )
by ignace nyamagana
15:08
created

EncloseField::addTo()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 2
dl 0
loc 21
ccs 10
cts 10
cp 1
crap 3
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * League.Csv (https://csv.thephpleague.com).
5
 *
6
 * @author  Ignace Nyamagana Butera <[email protected]>
7
 * @license https://github.com/thephpleague/csv/blob/master/LICENSE (MIT License)
8
 * @version 9.1.5
9
 * @link    https://github.com/thephpleague/csv
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
declare(strict_types=1);
16
17
namespace League\Csv;
18
19
use InvalidArgumentException;
20
use php_user_filter;
21
use function in_array;
22
use function str_replace;
23
use function strcspn;
24
use function stream_bucket_append;
25
use function stream_bucket_make_writeable;
26
use function stream_filter_register;
27
use function stream_get_filters;
28
use function strlen;
29
30
/**
31
 * A stream filter to improve enclosure character usage.
32
 *
33
 * @see https://tools.ietf.org/html/rfc4180#section-2
34
 * @see https://bugs.php.net/bug.php?id=38301
35
 *
36
 * @package League.csv
37
 * @since   9.0.0
38
 * @author  Ignace Nyamagana Butera <[email protected]>
39
 */
40
class EncloseField extends php_user_filter
41
{
42
    const FILTERNAME = 'convert.league.csv.enclosure';
43
44
    /**
45
     * the filter name used to instantiate the class with.
46
     *
47
     * @var string
48
     */
49
    public $filtername;
50
51
    /**
52
     * Contents of the params parameter passed to stream_filter_append
53
     * or stream_filter_prepend functions.
54
     *
55
     * @var mixed
56
     */
57
    public $params;
58
59
    /**
60
     * Default sequence.
61
     *
62
     * @var string
63
     */
64
    protected $sequence;
65
66
    /**
67
     * Characters that triggers enclosure in PHP.
68 2
     *
69
     * @var string
70 2
     */
71
    protected static $force_enclosure = "\n\r\t ";
72
73
    /**
74
     * Static method to return the stream filter filtername.
75
     */
76 2
    public static function getFiltername(): string
77
    {
78 2
        return self::FILTERNAME;
79 2
    }
80
81 2
    /**
82
     * Static method to register the class as a stream filter.
83
     */
84
    public static function register()
85
    {
86
        if (!in_array(self::FILTERNAME, stream_get_filters(), true)) {
87
            stream_filter_register(self::FILTERNAME, __CLASS__);
88
        }
89
    }
90
91
    /**
92
     * Static method to add the stream filter to a {@link Writer} object.
93 4
     *
94
     * @throws InvalidArgumentException if the sequence is malformed
95 4
     */
96
    public static function addTo(Writer $csv, string $sequence): Writer
97 4
    {
98 2
        self::register();
99
100
        if (!self::isValidSequence($sequence)) {
101 2
            throw new InvalidArgumentException('The sequence must contain at least one character to force enclosure');
102 2
        }
103 2
104
        $formatter = function (array $record) use ($sequence) {
105 2
            foreach ($record as &$value) {
106
                $value = $sequence.$value;
107 2
            }
108 2
            unset($value);
109
110
            return $record;
111 2
        };
112 2
113
        return $csv
114
            ->addFormatter($formatter)
115
            ->addStreamFilter(self::FILTERNAME, ['sequence' => $sequence]);
116
    }
117
118
    /**
119
     * Filter type and sequence parameters.
120
     *
121
     * The sequence to force enclosure MUST contains one of the following character ("\n\r\t ")
122
     */
123
    protected static function isValidSequence(string $sequence): bool
124 4
    {
125
        return strlen($sequence) != strcspn($sequence, self::$force_enclosure);
126 4
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function onCreate()
132 8
    {
133
        return isset($this->params['sequence'])
134 8
            && $this->isValidSequence($this->params['sequence']);
135 8
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function filter($in, $out, &$consumed, $closing)
141 2
    {
142
        while ($res = stream_bucket_make_writeable($in)) {
143 2
            $res->data = str_replace($this->params['sequence'], '', $res->data);
144 2
            $consumed += $res->datalen;
145 2
            stream_bucket_append($out, $res);
146 2
        }
147
148
        return PSFS_PASS_ON;
149 2
    }
150
}
151