Completed
Push — master ( c17605...0959b6 )
by Eric
03:55
created

CsvSerializationVisitor::encode()   D

Complexity

Conditions 10
Paths 18

Size

Total Lines 45
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 13.1047

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 4.8196
c 0
b 0
f 0
ccs 24
cts 35
cp 0.6857
cc 10
eloc 31
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 984 View Code Duplication
    public function __construct(
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...
52
        AccessorInterface $accessor,
53
        $delimiter = ',',
54
        $enclosure = '"',
55
        $escapeChar = '\\',
56
        $keySeparator = '.'
57
    ) {
58 984
        parent::__construct($accessor);
59
60 984
        $this->delimiter = $delimiter;
61 984
        $this->enclosure = $enclosure;
62 984
        $this->escapeChar = $escapeChar;
63 984
        $this->keySeparator = $keySeparator;
64 984
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 27 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 27
        if ($data === []) {
72 21
            return $this->visitData('[]', $type, $context);
73
        }
74
75 15
        return parent::visitArray($data, $type, $context);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 9
    public function visitBoolean($data, TypeMetadataInterface $type, ContextInterface $context)
82
    {
83 9
        return $this->visitData($data ? 'true' : 'false', $type, $context);
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 9 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 9
        $data = (string) $data;
92
93 9
        if (strpos($data, '.') === false) {
94 9
            $data .= '.0';
95 6
        }
96
97 9
        return $this->visitData($data, $type, $context);
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 147
    protected function encode($data)
104
    {
105 147
        $resource = fopen('php://temp,', 'w+');
106 147
        $headers = null;
107
108 147
        if (!is_array($data)) {
109 24
            $data = [[$data]];
110 139
        } elseif (!empty($data) && !$this->isIndexedArray($data)) {
111 120
            $data = [$data];
112 80
        }
113
114 147
        foreach ($data as $value) {
115 144
            $result = [];
116 144
            $this->flatten($value, $result);
117
118 144
            if ($headers === null) {
119 144
                if (!$this->isIndexedArray($result)) {
120 120
                    $headers = array_keys($result);
121 120
                    fputcsv($resource, $headers, $this->delimiter, $this->enclosure, $this->escapeChar);
122 80
                } else {
123 64
                    $headers = count($result);
124
                }
125 96
            } elseif (is_array($headers) && $headers !== array_keys($result)) {
126
                throw new \InvalidArgumentException(sprintf(
127
                    'The input dimension is not equals for all entries (Expected: %d, got %d).',
128
                    count($headers),
129
                    count($result)
130
                ));
131
            } elseif ($headers !== count($result)) {
132
                throw new \InvalidArgumentException(sprintf(
133
                    'The input dimension is not equals for all entries (Expected: %d, got %d).',
134
                    $headers,
135
                    count($result)
136
                ));
137
            }
138
139 144
            fputcsv($resource, $result, $this->delimiter, $this->enclosure, $this->escapeChar);
140 98
        }
141
142 147
        rewind($resource);
143 147
        $result = stream_get_contents($resource);
144 147
        fclose($resource);
145
146 147
        return $result;
147
    }
148
149
    /**
150
     * @param mixed[] $array
151
     * @param mixed[] $result
152
     * @param string  $parentKey
153
     */
154 144
    private function flatten(array $array, array &$result, $parentKey = '')
155
    {
156 144
        foreach ($array as $key => $value) {
157 144
            $key = $parentKey.$key;
158
159 144
            if ($value === []) {
160 6
                $value = null;
161 4
            }
162
163 144
            if (is_array($value)) {
164 18
                $this->flatten($value, $result, $key.$this->keySeparator);
165 12
            } else {
166 144
                $result[$key] = $value;
167
            }
168 96
        }
169 144
    }
170
171
    /**
172
     * @param mixed[] $array
173
     *
174
     * @return bool
175
     */
176 144
    private function isIndexedArray(array $array)
177
    {
178 144
        return ctype_digit(implode('', array_keys($array)));
179
    }
180
}
181