Data::write()   B
last analyzed

Complexity

Conditions 7
Paths 9

Size

Total Lines 50
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 25
c 1
b 0
f 0
nc 9
nop 1
dl 0
loc 50
ccs 0
cts 25
cp 0
crap 56
rs 8.5866
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