CsvDeserializationVisitor   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 134
Duplicated Lines 11.19 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 89.8%

Importance

Changes 0
Metric Value
dl 15
loc 134
c 0
b 0
f 0
wmc 16
lcom 1
cbo 1
ccs 44
cts 49
cp 0.898
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 15 15 1
A visitArray() 0 4 2
B decode() 0 56 9
A expand() 0 14 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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\Context\ContextInterface;
15
use Ivory\Serializer\Instantiator\InstantiatorInterface;
16
use Ivory\Serializer\Mapping\TypeMetadataInterface;
17
use Ivory\Serializer\Mutator\MutatorInterface;
18
use Ivory\Serializer\Visitor\AbstractDeserializationVisitor;
19
20
/**
21
 * @author GeLo <[email protected]>
22
 */
23
class CsvDeserializationVisitor extends AbstractDeserializationVisitor
24
{
25
    /**
26
     * @var string
27
     */
28
    private $delimiter;
29
30
    /**
31
     * @var string
32
     */
33
    private $enclosure;
34
35
    /**
36
     * @var string
37
     */
38
    private $escapeChar;
39
40
    /**
41
     * @var string
42
     */
43
    private $keySeparator;
44
45
    /**
46
     * @param InstantiatorInterface $instantiator
47
     * @param MutatorInterface      $mutator
48
     * @param string                $delimiter
49
     * @param string                $enclosure
50
     * @param string                $escapeChar
51
     * @param string                $keySeparator
52
     */
53 1492 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...
54
        InstantiatorInterface $instantiator,
55
        MutatorInterface $mutator,
56
        $delimiter = ',',
57
        $enclosure = '"',
58
        $escapeChar = '\\',
59
        $keySeparator = '.'
60
    ) {
61 1492
        parent::__construct($instantiator, $mutator);
62
63 1492
        $this->delimiter = $delimiter;
64 1492
        $this->enclosure = $enclosure;
65 1492
        $this->escapeChar = $escapeChar;
66 1492
        $this->keySeparator = $keySeparator;
67 1492
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 28
    public function visitArray($data, TypeMetadataInterface $type, ContextInterface $context)
73
    {
74 28
        return parent::visitArray($data === '[]' ? [] : $data, $type, $context);
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80 144
    protected function decode($data)
81
    {
82 144
        $result = $first = [];
83 144
        $headers = null;
84
85 144
        $resource = fopen('php://temp', 'r+');
86 144
        fwrite($resource, $data);
87 144
        rewind($resource);
88
89 144
        while (($fields = fgetcsv($resource, 0, $this->delimiter, $this->enclosure, $this->escapeChar)) !== false) {
90 144
            if ($fields === [null]) {
91 4
                continue;
92
            }
93
94 140
            $fieldsCount = count($fields);
95
96 140
            if ($headers === null) {
97 140
                $first = $fields;
98 140
                $headersCount = $fieldsCount;
99
100 140
                $headers = array_map(function ($value) {
101 140
                    return explode($this->keySeparator, $value);
102 140
                }, $fields);
103
104 140
                continue;
105
            }
106
107 108
            if ($fieldsCount !== $headersCount) {
0 ignored issues
show
Bug introduced by
The variable $headersCount does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
108
                throw new \InvalidArgumentException(sprintf(
109
                    'The input dimension is not equals for all entries (Expected: %d, got %d).',
110
                    $headersCount,
111
                    $fieldsCount
112
                ));
113
            }
114
115 108
            foreach ($fields as $key => $value) {
116 108
                $this->expand($headers[$key], $value, $result);
117
            }
118
        }
119
120 144
        fclose($resource);
121
122 144
        if (!empty($result)) {
123 108
            return $result;
124
        }
125
126 36
        if (empty($first)) {
127 4
            return;
128
        }
129
130 32
        if (count($first) === 1) {
131 32
            return reset($first);
132
        }
133
134
        return $first;
135
    }
136
137
    /**
138
     * @param string[] $paths
139
     * @param mixed    $data
140
     * @param mixed[]  $result
141
     */
142 108
    private function expand(array $paths, $data, array &$result)
143
    {
144 108
        $path = array_shift($paths);
145
146 108
        if (empty($paths)) {
147 108
            $result[$path] = $data !== '' ? $data : null;
148
        } else {
149 20
            if (!isset($result[$path])) {
150 20
                $result[$path] = [];
151
            }
152
153 20
            $this->expand($paths, $data, $result[$path]);
154
        }
155 108
    }
156
}
157