Data::read()   B
last analyzed

Complexity

Conditions 11
Paths 20

Size

Total Lines 60
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 11
eloc 39
c 3
b 0
f 0
nc 20
nop 1
dl 0
loc 60
ccs 0
cts 37
cp 0
crap 132
rs 7.3166

How to fix   Long Method    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
namespace SPSS\Sav\Record;
4
5
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
6
use SebastianBergmann\CodeCoverage\Util;
0 ignored issues
show
Bug introduced by
The type SebastianBergmann\CodeCoverage\Util was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use SPSS\Buffer;
8
use SPSS\ByteCodeReader;
9
use SPSS\ByteCodeWriter;
10
use SPSS\Exception;
11
use SPSS\Sav\Record;
12
use SPSS\Utils;
13
14
class Data extends Record
15
{
16
    const TYPE = 999;
17
    /**
18
     * @var array [case_index][var_index]
19
     */
20
    public $matrix = [];
21
22
    /**
23
     * @param Buffer $buffer
24
     * @throws Exception
25
     */
26
    public function read(Buffer $buffer)
27
    {
28
29
        if ($buffer->readInt() != 0) {
30
            throw new \InvalidArgumentException('Error reading data record. Non-zero value found.');
31
        }
32
        if (! isset($buffer->context->variables)) {
33
            throw new \InvalidArgumentException('Variables required');
34
        }
35
        if (! isset($buffer->context->header)) {
36
            throw new \InvalidArgumentException('Header required');
37
        }
38
        if (! isset($buffer->context->info)) {
39
            throw new \InvalidArgumentException('Info required');
40
        }
41
42
        $compressed = $buffer->context->header->compression;
0 ignored issues
show
Unused Code introduced by
The assignment to $compressed is dead and can be removed.
Loading history...
43
        $bias = $buffer->context->header->bias;
0 ignored issues
show
Unused Code introduced by
The assignment to $bias is dead and can be removed.
Loading history...
44
        $casesCount = $buffer->context->header->casesCount;
45
46
        /** @var Record\Info[] $info */
47
        $info = $buffer->context->info;
48
49
50
        if (isset($info[Record\Info\VeryLongString::SUBTYPE])) {
51
            $veryLongStrings = $info[Record\Info\VeryLongString::SUBTYPE]->toArray();
52
        } else {
53
            $veryLongStrings = [];
54
        }
55
56
        /** @var Variable[] $variables */
57
        $variables = $buffer->context->variables;
58
59
        if (isset($info[Record\Info\MachineFloatingPoint::SUBTYPE])) {
60
            $sysmis = $info[Record\Info\MachineFloatingPoint::SUBTYPE]->sysmis;
0 ignored issues
show
Unused Code introduced by
The assignment to $sysmis is dead and can be removed.
Loading history...
61
        } else {
62
            $sysmis = NAN;
63
        }
64
65
        $reader = new ByteCodeReader($buffer);
66
        for ($case = 0; $case < $casesCount; $case++) {
67
            $varNum = 0;
68
69
            for($index = 0; $index < count($variables); $index++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
70
                $var = $variables[$index];
71
                $isNumeric = \SPSS\Sav\Variable::isNumberFormat($var->write[1]);
72
                if ($isNumeric) {
73
                    $data = $reader->read(8);
74
                    $this->matrix[$case][$varNum] = unpack('d', $data)[1];
75
                } else {
76
                    $value = '';
77
                    foreach(Utils::getSegments($veryLongStrings[$var->name] ?? $var->width) as $segmentWidth) {
78
                        $segment = $reader->read($segmentWidth + (8 - ($segmentWidth % 8)) % 8);
79
                        $value .= rtrim($segment);
80
                        $index++;
81
                    }
82
                    $index--;
83
                    $this->matrix[$case][$varNum] = $value;
84
                }
85
                $varNum++;
86
            }
87
88
        }
89
    }
90
91
    /**
92
     * @param Buffer $buffer
93
     */
94
    public function write(Buffer $buffer)
95
    {
96
        $buffer->writeInt(self::TYPE);
97
        $buffer->writeInt(0);
98
99
100
        if (! isset($buffer->context->variables)) {
101
            throw new \InvalidArgumentException('Variables required');
102
        }
103
        if (! isset($buffer->context->header)) {
104
            throw new \InvalidArgumentException('Header required');
105
        }
106
        if (! isset($buffer->context->info)) {
107
            throw new \InvalidArgumentException('Info required');
108
        }
109
110
        $casesCount = $buffer->context->header->casesCount;
111
112
        /** @var Variable[] $variables */
113
        $variables = $buffer->context->variables;
114
115
        /** @var Record\Info[] $info */
116
        $info = $buffer->context->info;
117
118
        if (isset($info[Record\Info\MachineFloatingPoint::SUBTYPE])) {
119
            $sysmis = $info[Record\Info\MachineFloatingPoint::SUBTYPE]->sysmis;
0 ignored issues
show
Unused Code introduced by
The assignment to $sysmis is dead and can be removed.
Loading history...
120
        } else {
121
            $sysmis = NAN;
122
        }
123
124
        /** @var Record\Info\VeryLongString $vls */
125
        $veryLongStrings = $info[Record\Info\VeryLongString::SUBTYPE];
126
127
        $dataBuffer = Buffer::factory('', ['memory' => true]);
128
129
        $writer = new ByteCodeWriter($dataBuffer);
130
        for ($case = 0; $case < $casesCount; $case++) {
131
            /**
132
             * @var  $index
133
             * @var Variable $variable
134
             */
135
            foreach ($variables as $index => $variable) {
136
                $width = $veryLongStrings[$variable->name] ?? $variable->width;
137
                $value = $this->matrix[$case][$index];
138
                $this->writeVariable($writer, $variable, $width, $value);
139
            }
140
        }
141
142
        $dataBuffer->rewind();
143
        $buffer->writeStream($dataBuffer->getStream());
144
    }
145
146
    private function writeVariable(
147
        ByteCodeWriter $writer,
148
        Variable $variable,
149
        int $width,
150
        $value
151
    ) {
152
        $isNumeric = \SPSS\Sav\Variable::isNumberFormat($variable->write[1]);
153
        if ($isNumeric) {
154
            $writer->append(pack('d', $value));
155
            $writer->flush();
156
        } else {
157
            foreach(Utils::getSegments($width) as $segmentWidth) {
158
                $segment = str_pad(substr($value, 0, $segmentWidth), $segmentWidth);
159
                $padding = str_repeat(' ', (8 - (strlen($segment) % 8)) % 8);
160
                $writer->append($segment);
161
                $writer->append($padding);
162
                $writer->flush();
163
                $value = substr($value, $segmentWidth);
164
            }
165
        }
166
    }
167
168
169
    /**
170
     * @return array
171
     */
172
    public function toArray()
173
    {
174
        return $this->matrix;
175
    }
176
}
177