Passed
Push — 4.0 ( 22a861...17fe63 )
by De
02:37
created

AbstractNotPartitionedDatabase::buildIndex()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 50
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 24
nc 10
nop 0
dl 0
loc 50
rs 8.0555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Sokil\IsoCodes;
6
7
/**
8
 * Abstract collection of ISO entries loaded from single file
9
 */
10
abstract class AbstractNotPartitionedDatabase extends AbstractDatabase
11
{
12
    /**
13
     * Index to search by entry field's values
14
     *
15
     * {indexedFieldName => {indexedFieldValue => entryObject}}
16
     *
17
     * @psalm-var Array<string, Array<string, object>>
18
     * @var object[][]
19
     */
20
    private $index;
21
22
    /**
23
     * List of entry fields to be indexed and searched.
24
     * May be override in child classes to search by indexed fields.
25
     *
26
     * @return mixed[]
27
     */
28
    protected function getIndexDefinition(): array
29
    {
30
        return [];
31
    }
32
33
    private function buildIndex(): void
34
    {
35
        // init empty index
36
        $this->index = [];
37
38
        // get index definition
39
        $indexedFields = $this->getIndexDefinition();
40
41
        // build index for database
42
        if (!empty($indexedFields)) {
43
            // init all defined indexes
44
            foreach ($this->getClusterIndex() as $entryArray) {
45
                $entry = $this->arrayToEntry($entryArray);
46
                foreach ($indexedFields as $indexName => $indexDefinition) {
47
                    if (is_array($indexDefinition)) {
48
                        // compound index
49
                        // iteratively create hierarchy of array indexes
50
                        $reference = &$this->index[$indexName];
51
                        foreach ($indexDefinition as $indexDefinitionPart) {
52
                            if (is_array($indexDefinitionPart)) {
53
                                // limited length of field
54
                                $indexDefinitionPartValue = substr(
55
                                    $entryArray[$indexDefinitionPart[0]],
56
                                    0,
57
                                    $indexDefinitionPart[1]
58
                                );
59
                            } else {
60
                                $indexDefinitionPartValue = $entryArray[$indexDefinitionPart];
61
                            }
62
63
                            if (!isset($reference[$indexDefinitionPartValue])) {
64
                                $reference[$indexDefinitionPartValue] = [];
65
                            }
66
67
                            $reference = &$reference[$indexDefinitionPartValue];
68
                        }
69
70
                        // add value
71
                        $reference = $entry;
72
                    } else {
73
                        // single index
74
                        $indexName = $indexDefinition;
75
76
                        // skip empty field
77
                        if (empty($entryArray[$indexDefinition])) {
78
                            continue;
79
                        }
80
81
                        // add to indexUA
82
                        $this->index[$indexName][$entryArray[$indexDefinition]] = $entry;
83
                    }
84
                }
85
            }
86
        }
87
    }
88
89
    /**
90
     * @return mixed[]
91
     *
92
     * @throws \InvalidArgumentException If no index found in database
93
     */
94
    private function getIndex(string $indexedFieldName): array
95
    {
96
        // build index
97
        if ($this->index === null) {
98
            $this->buildIndex();
99
        }
100
101
        // get index
102
        if (!isset($this->index[$indexedFieldName])) {
103
            throw new \InvalidArgumentException(
104
                sprintf(
105
                    'Unknown index "%s" in database "%s"',
106
                    $indexedFieldName,
107
                    get_class()
108
                )
109
            );
110
        }
111
112
        return $this->index[$indexedFieldName];
113
    }
114
115
    /**
116
     * @param string $indexedFieldName
117
     * @param string $fieldValue
118
     *
119
     * @return null|object|object[] null when not found, object when found by single-field index,
120
     *         object[] when found by compound index
121
     */
122
    protected function find(string $indexedFieldName, string $fieldValue)
123
    {
124
        $fieldIndex = $this->getIndex($indexedFieldName);
125
126
        return $fieldIndex[$fieldValue] ?? null;
127
    }
128
}
129