Passed
Push — master ( 45b054...06b8db )
by Sam
02:37
created

Data::writeVariable()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 12
c 0
b 0
f 0
nc 3
nop 4
dl 0
loc 18
ccs 12
cts 12
cp 1
crap 3
rs 9.8666
1
<?php
2
3
namespace SPSS\Sav\Record;
4
5
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
6
use SebastianBergmann\CodeCoverage\Util;
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 5
    public function read(Buffer $buffer)
27
    {
28
29 5
        if ($buffer->readInt() != 0) {
30
            throw new \InvalidArgumentException('Error reading data record. Non-zero value found.');
31
        }
32 5
        if (! isset($buffer->context->variables)) {
33
            throw new \InvalidArgumentException('Variables required');
34
        }
35 5
        if (! isset($buffer->context->header)) {
36
            throw new \InvalidArgumentException('Header required');
37
        }
38 5
        if (! isset($buffer->context->info)) {
39
            throw new \InvalidArgumentException('Info required');
40
        }
41
42 5
        $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 5
        $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 5
        $casesCount = $buffer->context->header->casesCount;
45
46
        /** @var Record\Info[] $info */
47 5
        $info = $buffer->context->info;
48
49
50 5
        if (isset($info[Record\Info\VeryLongString::SUBTYPE])) {
51 1
            $veryLongStrings = $info[Record\Info\VeryLongString::SUBTYPE]->toArray();
52
        } else {
53 4
            $veryLongStrings = [];
54
        }
55
56
        /** @var Variable[] $variables */
57 5
        $variables = $buffer->context->variables;
58
59 5
        if (isset($info[Record\Info\MachineFloatingPoint::SUBTYPE])) {
60 5
            $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 5
        $reader = new ByteCodeReader($buffer);
66 5
        for ($case = 0; $case < $casesCount; $case++) {
67 4
            $varNum = 0;
68
69 4
            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 4
                $var = $variables[$index];
71 4
                $isNumeric = \SPSS\Sav\Variable::isNumberFormat($var->write[1]);
72 4
                if ($isNumeric) {
73 3
                    $data = $reader->read(8);
74 3
                    $this->matrix[$case][$varNum] = unpack('d', $data)[1];
75
                } else {
76 4
                    $value = '';
77 4
                    foreach(Utils::getSegments($veryLongStrings[$var->name] ?? $var->width) as $segmentWidth) {
78 4
                        $segment = $reader->read($segmentWidth + 8 - ($segmentWidth % 8));
79 4
                        $value .= rtrim($segment);
80 4
                        $index++;
81
                    }
82 4
                    $index--;
83 4
                    $this->matrix[$case][$varNum] = $value;
84
                }
85 4
                $varNum++;
86
            }
87
88
        }
89 5
    }
90
91
    /**
92
     * @param Buffer $buffer
93
     */
94 5
    public function write(Buffer $buffer)
95
    {
96 5
        $buffer->writeInt(self::TYPE);
97 5
        $buffer->writeInt(0);
98
99
100 5
        if (! isset($buffer->context->variables)) {
101
            throw new \InvalidArgumentException('Variables required');
102
        }
103 5
        if (! isset($buffer->context->header)) {
104
            throw new \InvalidArgumentException('Header required');
105
        }
106 5
        if (! isset($buffer->context->info)) {
107
            throw new \InvalidArgumentException('Info required');
108
        }
109
110 5
        $casesCount = $buffer->context->header->casesCount;
111
112
        /** @var Variable[] $variables */
113 5
        $variables = $buffer->context->variables;
114
115
        /** @var Record\Info[] $info */
116 5
        $info = $buffer->context->info;
117
118 5
        if (isset($info[Record\Info\MachineFloatingPoint::SUBTYPE])) {
119 5
            $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 5
        $veryLongStrings = $info[Record\Info\VeryLongString::SUBTYPE];
126
127 5
        $dataBuffer = Buffer::factory('', ['memory' => true]);
128
129 5
        $writer = new ByteCodeWriter($dataBuffer);
130 5
        for ($case = 0; $case < $casesCount; $case++) {
131
            /**
132
             * @var  $index
133
             * @var Variable $variable
134
             */
135 4
            foreach ($variables as $index => $variable) {
136 4
                $width = $veryLongStrings[$variable->name] ?? $variable->width;
137 4
                $value = $this->matrix[$case][$index];
138 4
                $this->writeVariable($writer, $variable, $width, $value);
139
            }
140
        }
141
142 5
        $dataBuffer->rewind();
143 5
        $buffer->writeStream($dataBuffer->getStream());
144 5
    }
145
146 4
    private function writeVariable(
147
        ByteCodeWriter $writer,
148
        Variable $variable,
149
        int $width,
150
        $value
151
    ) {
152 4
        $isNumeric = \SPSS\Sav\Variable::isNumberFormat($variable->write[1]);
153 4
        if ($isNumeric) {
154 3
            $writer->append(pack('d', $value));
155 3
            $writer->flush();
156
        } else {
157 4
            foreach(Utils::getSegments($width) as $segmentWidth) {
158 4
                $segment = str_pad(substr($value, 0, $segmentWidth), $segmentWidth);
159 4
                $padding = str_repeat(' ', 8 - (strlen($segment) % 8));
160 4
                $writer->append($segment);
161 4
                $writer->append($padding);
162 4
                $writer->flush();
163 4
                $value = substr($value, $segmentWidth);
164
            }
165
        }
166 4
    }
167
168
169
    /**
170
     * @return array
171
     */
172 5
    public function toArray()
173
    {
174 5
        return $this->matrix;
175
    }
176
}
177