Failed Conditions
Push — master ( 305cd8...275760 )
by Daniel S.
03:34 queued 18s
created

DBCRecord   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 92.86%

Importance

Changes 0
Metric Value
eloc 50
dl 0
loc 122
ccs 39
cts 42
cp 0.9286
rs 10
c 0
b 0
f 0
wmc 15

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
C read() 0 53 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Wowstack\Dbc;
6
7
/**
8
 * Implements a single record within a DBC file.
9
 */
10
class DBCRecord
11
{
12
    /**
13
     * @var DBC
14
     */
15
    protected $dbcFile = null;
16
17
    /**
18
     * @var int
19
     */
20
    protected $position = 0;
21
22
    /**
23
     * @var int
24
     */
25
    protected $recordOffset = 0;
26
27
    /**
28
     * @var int
29
     */
30
    protected $recordSize = 0;
31
32
    /**
33
     * @var resource
34
     */
35
    protected $fileHandle = null;
36
37
    /**
38
     * @var mixed
39
     */
40
    protected $data = null;
41
42
    /**
43
     * @var int
44
     */
45
    protected $identifier = 0;
46
47
    /**
48
     * Constructs a new DBC row.
49
     *
50
     * @param DBC $dbcFile
51
     * @param int $position
52
     */
53 5
    public function __construct(DBC $dbcFile, int $position)
54
    {
55 5
        $this->dbcFile = $dbcFile;
56 5
        $this->position = $position;
57
58 5
        $this->recordSize = $this->dbcFile->getRecordSize();
59 5
        $this->recordOffset = DBC::HEADER_SIZE + $this->position * $this->recordSize;
60 5
        $this->fileHandle = $this->dbcFile->getFileHandle();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->dbcFile->getFileHandle() can also be of type boolean. However, the property $fileHandle is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
61
62 5
        if (false === $this->fileHandle) {
63
            throw new DBCException('DBC file is not readable.');
64
        }
65
66 5
        fseek($this->fileHandle, $this->recordOffset);
0 ignored issues
show
Bug introduced by
It seems like $this->fileHandle can also be of type true; however, parameter $handle of fseek() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

66
        fseek(/** @scrutinizer ignore-type */ $this->fileHandle, $this->recordOffset);
Loading history...
67 5
        if ($this->recordSize > 0) {
68 5
            $this->data = fread($this->fileHandle, $this->recordSize);
0 ignored issues
show
Bug introduced by
It seems like $this->fileHandle can also be of type true; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
            $this->data = fread(/** @scrutinizer ignore-type */ $this->fileHandle, $this->recordSize);
Loading history...
69
        }
70 5
    }
71
72
    /**
73
     * Reads the current row into key/value array.
74
     *
75
     * @return array
76
     *
77
     * @throws DBCException
78
     */
79 4
    public function read(): array
80
    {
81 4
        $map = $this->dbcFile->getMap();
82 4
        if (empty($map)) {
83 1
            throw new DBCException('DBCRecord can not be read without a mapping');
84
        }
85
86 3
        $format = [];
87 3
        $strings = [];
88 3
        $foreignKeys = [];
89 3
        $fields = $map->getParsedFields();
90
91 3
        foreach ($fields as $fieldName => $fieldData) {
92 3
            $format[] = $fieldData['format'];
93 3
            if ('string' === $fieldData['type'] || 'localized_string' === $fieldData['type']) {
94 2
                $strings[] = $fieldName;
95
            }
96 3
            if ('foreign_key' === $fieldData['type']) {
97 3
                $foreignKeys[] = $fieldName;
98
            }
99
        }
100
101 3
        $format = implode('/', $format);
102 3
        $data = unpack($format, $this->data);
103
104
        // This ensure that string fields will be empty strings instead of 0.
105 3
        foreach ($strings as $string) {
106 2
            $stringPointer = $data[$string];
107 2
            if ($data[$string] > 0) {
108
                try {
109 2
                    $data[$string] = $this->dbcFile->getString($data[$string]);
110
                } catch (DBCException $dbcException) {
111
                    $data[$string] = '';
112 2
                    $this->dbcFile->addError('string', $this->position, $string, 'String pointer not found at offset '.$stringPointer);
0 ignored issues
show
Coding Style introduced by
Concat operator must be surrounded by a single space
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
113
                }
114
            } else {
115 2
                $data[$string] = '';
116
            }
117
        }
118
119
        // This ensures fields containing references to other tables will be nulled
120
        // if they do not contain a valid reference.
121 3
        foreach ($foreignKeys as $foreignKey) {
122 1
            if ($data[$foreignKey] <= 0) {
123 1
                $data[$foreignKey] = null;
124
            }
125
        }
126
127
        $data = array_filter($data, function ($key) {
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type false; however, parameter $input of array_filter() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

127
        $data = array_filter(/** @scrutinizer ignore-type */ $data, function ($key) {
Loading history...
128 3
            return false === strpos($key, '_checksum') && false === strpos($key, '_unused');
129 3
        }, ARRAY_FILTER_USE_KEY);
130
131 3
        return $data;
132
    }
133
}
134