Passed
Push — main ( 633b92...66245a )
by Dimitri
12:27
created

CsvFormatter::format()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 45
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 20
c 1
b 0
f 0
nc 13
nop 1
dl 0
loc 45
rs 8.6666
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Formatter;
13
14
/**
15
 * Formateur de données en CSV
16
 *
17
 * @see http://www.metashock.de/2014/02/create-csv-file-in-memory-php/
18
 */
19
class CsvFormatter implements FormatterInterface
20
{
21
    /**
22
     * Délimiteur de champ (un seul caractère)
23
     *
24
     * @var string
25
     */
26
    private $delimiter = ',';
27
28
    /**
29
     * Encadrement du champ (un seul caractère).
30
     *
31
     * @var string
32
     */
33
    private $enclosure = '"';
34
35
    /**
36
     * {@inheritDoc}
37
     *
38
     * @return string|null Une chaine formatée en CSV
39
     */
40
    public function format($data)
41
    {
42
        // Utiliser un seuil de 1 Mo (1024 * 1024)
43
        $handle = fopen('php://temp/maxmemory:1048576', 'wb');
44
        if ($handle === false) {
45
            return null;
46
        }
47
48
        if (! is_array($data)) {
49
            $data = (array) $data;
50
        }
51
52
        // Vérifie s'il s'agit d'un tableau multidimensionnel
53
        if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE)) {
54
            $headings = array_keys($data[0]);
55
        } else {
56
            $headings = array_keys($data);
57
            $data     = [$data];
58
        }
59
60
        // Appliquer les en-têtes
61
        fputcsv($handle, $headings, $this->delimiter, $this->enclosure);
62
63
        foreach ($data as $record) {
64
            // Si l'enregistrement n'est pas un tableau, alors break.
65
            // C'est parce que le 2ème paramètre de fputcsv() doit être un tableau
66
            if (! is_array($record)) {
67
                break;
68
            }
69
70
            // Suppression de la notification "conversion de tableau en chaîne".
71
            // Gardez le "mal" @ ici.
72
            $record = @array_map('strval', $record);
73
74
            fputcsv($handle, $record, $this->delimiter, $this->enclosure);
75
        }
76
77
        rewind($handle);
78
79
        $csv = stream_get_contents($handle);
80
81
        fclose($handle);
82
83
        // Convertit l'encodage UTF-8 en UTF-16LE qui est pris en charge par MS Excel
84
        return mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi...v, 'UTF-16LE', 'UTF-8') also could return the type array which is incompatible with the documented return type null|string.
Loading history...
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     *
90
     * @param string $data Chaine CSV
91
     *
92
     * @return array A multi-dimensional array with the outer array being the number of rows
93
     *               and the inner arrays the individual fields
94
     */
95
    public function parse(string $data): array
96
    {
97
        return str_getcsv($data, $this->delimiter, $this->enclosure);
98
    }
99
100
    /**
101
     * Recupère le délimiteur de champ
102
     */
103
    public function getDelimiter(): string
104
    {
105
        return $this->delimiter;
106
    }
107
108
    /**
109
     * Définit le délimiteur de champ
110
     */
111
    public function setDelimiter(string $delimiter): self
112
    {
113
        $this->delimiter = $delimiter[0] ?? ',';
114
115
        return $this;
116
    }
117
118
    /**
119
     * Recupère l'encadrement du champ (un seul caractère).
120
     */
121
    public function getEnclosure(): string
122
    {
123
        return $this->enclosure;
124
    }
125
126
    /**
127
     * Set définit l'encadrement du champ (un seul caractère).
128
     */
129
    public function setEnclosure(string $enclosure): self
130
    {
131
        $this->enclosure = $enclosure[0] ?? '"';
132
133
        return $this;
134
    }
135
}
136