Completed
Push — master ( f2b3c9...88814d )
by Eric
65:21
created

CsvSerializationVisitor::encode()   C

Complexity

Conditions 10
Paths 18

Size

Total Lines 49
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 13.1047

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 24
cts 35
cp 0.6857
rs 5.5471
c 0
b 0
f 0
cc 10
eloc 33
nc 18
nop 1
crap 13.1047

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Ivory Serializer package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ivory\Serializer\Visitor\Csv;
13
14
use Ivory\Serializer\Accessor\AccessorInterface;
15
use Ivory\Serializer\Context\ContextInterface;
16
use Ivory\Serializer\Mapping\TypeMetadataInterface;
17
use Ivory\Serializer\Visitor\AbstractSerializationVisitor;
18
19
/**
20
 * @author GeLo <[email protected]>
21
 */
22
class CsvSerializationVisitor extends AbstractSerializationVisitor
23
{
24
    /**
25
     * @var string
26
     */
27
    private $delimiter;
28
29
    /**
30
     * @var string
31
     */
32
    private $enclosure;
33
34
    /**
35
     * @var string
36
     */
37
    private $escapeChar;
38
39
    /**
40
     * @var string
41
     */
42
    private $keySeparator;
43
44
    /**
45
     * @param AccessorInterface $accessor
46
     * @param string            $delimiter
47
     * @param string            $enclosure
48
     * @param string            $escapeChar
49
     * @param string            $keySeparator
50
     */
51 1376
    public function __construct(
52
        AccessorInterface $accessor,
53
        $delimiter = ',',
54
        $enclosure = '"',
55
        $escapeChar = '\\',
56
        $keySeparator = '.'
57
    ) {
58 1376
        parent::__construct($accessor);
59
60 1376
        $this->delimiter = $delimiter;
61 1376
        $this->enclosure = $enclosure;
62 1376
        $this->escapeChar = $escapeChar;
63 1376
        $this->keySeparator = $keySeparator;
64 1376
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 40 View Code Duplication
    public function visitArray($data, TypeMetadataInterface $type, ContextInterface $context)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70
    {
71 40
        if ($data === []) {
72 28
            return $this->visitData('[]', $type, $context);
73
        }
74
75 24
        return parent::visitArray($data, $type, $context);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 12
    public function visitBoolean($data, TypeMetadataInterface $type, ContextInterface $context)
82
    {
83 12
        return $this->visitData($data ? 'true' : 'false', $type, $context);
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 12 View Code Duplication
    public function visitFloat($data, TypeMetadataInterface $type, ContextInterface $context)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
    {
91 12
        $data = (string) $data;
92
93 12
        if (strpos($data, '.') === false) {
94 12
            $data .= '.0';
95 6
        }
96
97 12
        return $this->visitData($data, $type, $context);
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 204
    protected function encode($data)
104
    {
105 204
        $resource = fopen('php://temp,', 'w+');
106 204
        $headers = null;
107
108 204
        if (!is_array($data)) {
109 32
            $data = [[$data]];
110 188
        } elseif (!empty($data) && !$this->isIndexedArray($data)) {
111 168
            $data = [$data];
112 84
        }
113
114 204
        foreach ($data as $value) {
115 200
            $result = [];
116 200
            $this->flatten($value, $result);
117
118 200
            if ($headers === null) {
119 200
                if (!$this->isIndexedArray($result)) {
120 168
                    $headers = array_keys($result);
121 168
                    fputcsv($resource, $headers, $this->delimiter, $this->enclosure, $this->escapeChar);
122 84
                } else {
123 116
                    $headers = count($result);
124
                }
125 100
            } elseif (is_array($headers) && $headers !== array_keys($result)) {
126
                fclose($resource);
127
128
                throw new \InvalidArgumentException(sprintf(
129
                    'The input dimension is not equals for all entries (Expected: %d, got %d).',
130
                    count($headers),
131
                    count($result)
132
                ));
133
            } elseif ($headers !== count($result)) {
134
                fclose($resource);
135
136
                throw new \InvalidArgumentException(sprintf(
137
                    'The input dimension is not equals for all entries (Expected: %d, got %d).',
138
                    $headers,
139 200
                    count($result)
140 102
                ));
141
            }
142 204
143 204
            fputcsv($resource, $result, $this->delimiter, $this->enclosure, $this->escapeChar);
144 204
        }
145
146 204
        rewind($resource);
147
        $result = stream_get_contents($resource);
148
        fclose($resource);
149
150
        return $result;
151
    }
152
153
    /**
154 200
     * @param mixed[] $array
155
     * @param mixed[] $result
156 200
     * @param string  $parentKey
157 200
     */
158
    private function flatten(array $array, array &$result, $parentKey = '')
159 200
    {
160 8
        foreach ($array as $key => $value) {
161 4
            $key = $parentKey.$key;
162
163 200
            if ($value === []) {
164 28
                $value = null;
165 14
            }
166 200
167
            if (is_array($value)) {
168 100
                $this->flatten($value, $result, $key.$this->keySeparator);
169 200
            } else {
170
                $result[$key] = is_string($value) ? str_replace(PHP_EOL, '', $value) : $value;
171
            }
172
        }
173
    }
174
175
    /**
176 200
     * @param mixed[] $array
177
     *
178 200
     * @return bool
179
     */
180
    private function isIndexedArray(array $array)
181
    {
182
        return ctype_digit(implode('', array_keys($array)));
183
    }
184
}
185