CsvFormatter::validate()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 10
cts 10
cp 1
rs 8.9457
c 0
b 0
f 0
cc 6
nc 4
nop 1
crap 6
1
<?php
2
namespace Consolidation\OutputFormatters\Formatters;
3
4
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
5
use Consolidation\OutputFormatters\Options\FormatterOptions;
6
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
7
use Consolidation\OutputFormatters\Transformations\TableTransformation;
8
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
/**
12
 * Comma-separated value formatters
13
 *
14
 * Display the provided structured data in a comma-separated list. If
15
 * there are multiple records provided, then they will be printed
16
 * one per line.  The primary data types accepted are RowsOfFields and
17
 * PropertyList. The later behaves exactly like the former, save for
18
 * the fact that it contains but a single row. This formmatter can also
19
 * accept a PHP array; this is also interpreted as a single-row of data
20
 * with no header.
21
 */
22
class CsvFormatter implements FormatterInterface, ValidDataTypesInterface, RenderDataInterface
23
{
24
    use ValidDataTypesTrait;
25 12
    use RenderTableDataTrait;
26
27
    public function validDataTypes()
28
    {
29
        return
30 12
            [
31 1
                new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields'),
32 1
                new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\PropertyList'),
33 1
                new \ReflectionClass('\ArrayObject'),
34
            ];
35 1
    }
36 1
37 1
    public function validate($structuredData)
38
    {
39 1
        // If the provided data was of class RowsOfFields
40
        // or PropertyList, it will be converted into
41
        // a TableTransformation object.
42
        if (!is_array($structuredData) && (!$structuredData instanceof TableTransformation)) {
43 11
            throw new IncompatibleDataException(
44 6
                $this,
45 6
                $structuredData,
46 5
                $this->validDataTypes()
47
            );
48 1
        }
49 6
        // If the data was provided to us as a single array, then
50
        // convert it to a single row.
51
        if (is_array($structuredData) && !empty($structuredData)) {
52
            $firstRow = reset($structuredData);
53
            if (!is_array($firstRow)) {
54
                return [$structuredData];
55 11
            }
56
        }
57
        return $structuredData;
58 11
    }
59
60
    /**
61 11
     * Return default values for formatter options
62 5
     * @return array
63 5
     */
64 5
    protected function getDefaultFormatterOptions()
65
    {
66 11
        return [
67 11
            FormatterOptions::INCLUDE_FIELD_LABELS => true,
68 11
            FormatterOptions::DELIMITER => ',',
69 11
            FormatterOptions::CSV_ENCLOSURE => '"',
70
            FormatterOptions::CSV_ESCAPE_CHAR => "\\",
71 11
        ];
72
    }
73 11
74 11
    /**
75
     * @inheritdoc
76 11
     */
77
    public function write(OutputInterface $output, $data, FormatterOptions $options)
78 11
    {
79 11
        $defaults = $this->getDefaultFormatterOptions();
80 11
81 11
        $includeFieldLabels = $options->get(FormatterOptions::INCLUDE_FIELD_LABELS, $defaults);
82 11
        if ($includeFieldLabels && ($data instanceof TableTransformation)) {
83 11
            $headers = $data->getHeaders();
84
            $this->writeOneLine($output, $headers, $options);
85
        }
86
87
        foreach ($data as $line) {
88
            $this->writeOneLine($output, $line, $options);
89
        }
90
    }
91
92
  /**
93
   * Writes a single a single line of formatted CSV data to the output stream.
94
   *
95
   * @param OutputInterface $output the output stream to write to.
96
   * @param array $data an array of field data to convert to a CSV string.
97
   * @param FormatterOptions $options the specified options for this formatter.
98
   */
99
    protected function writeOneLine(OutputInterface $output, $data, $options)
100
    {
101
        $defaults = $this->getDefaultFormatterOptions();
102
        $delimiter = $options->get(FormatterOptions::DELIMITER, $defaults);
103
        $enclosure = $options->get(FormatterOptions::CSV_ENCLOSURE, $defaults);
104
        $escapeChar = $options->get(FormatterOptions::CSV_ESCAPE_CHAR, $defaults);
105
        $output->write($this->csvEscape($data, $delimiter, $enclosure, $escapeChar));
0 ignored issues
show
Bug introduced by
It seems like $this->csvEscape($data, ...enclosure, $escapeChar) targeting Consolidation\OutputForm...vFormatter::csvEscape() can also be of type boolean; however, Symfony\Component\Consol...utputInterface::write() does only seem to accept string|object<Symfony\Co...onsole\Output\iterable>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
106
    }
107
108
  /**
109
   * Generates a CSV-escaped string from an array of field data.
110
   *
111
   * @param array $data an array of field data to format as a CSV.
112
   * @param string $delimiter the delimiter to use between fields.
113
   * @param string $enclosure character to use when enclosing complex fields.
114
   * @param string $escapeChar character to use when escaping special characters.
115
   *
116
   * @return string|bool the formatted CSV string, or FALSE if the formatting failed.
117
   */
118
    protected function csvEscape($data, $delimiter = ',', $enclosure = '"', $escapeChar = "\\")
119
    {
120
        $buffer = fopen('php://temp', 'r+');
121
        if (version_compare(PHP_VERSION, '5.5.4', '>=')) {
122
            fputcsv($buffer, $data, $delimiter, $enclosure, $escapeChar);
123
        } else {
124
            fputcsv($buffer, $data, $delimiter, $enclosure);
125
        }
126
        rewind($buffer);
127
        $csv = fgets($buffer);
128
        fclose($buffer);
129
        return $csv;
130
    }
131
}
132