Passed
Push — master ( 9084ca...59b574 )
by De
02:05
created

AbstractDatabase::rewind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Sokil\IsoCodes;
4
5
/**
6
 * Abstract collection of ISO entries
7
 */
8
abstract class AbstractDatabase implements \Iterator, \Countable
9
{
10
    /**
11
     * Path to ISO databases
12
     */
13
    const DATABASE_PATH = '/../databases';
14
15
    /**
16
     * Path to gettext localised messages
17
     */
18
    const MESSAGES_PATH = '/../messages';
19
20
    /**
21
     * @var array[]
22
     */
23
    private $clusterIndex = [];
24
25
    /**
26
     * Index to search by entry field's values
27
     *
28
     * @var array
29
     */
30
    private $index = [];
31
32
    public function __construct()
33
    {
34
        $this->loadDatabase($this->getDatabaseFilePath());
35
    }
36
37
    /**
38
     * ISO Standard Number
39
     *
40
     * @return string
41
     */
42
    abstract public static function getISONumber();
43
44
    /**
45
     * @param array $entry
46
     *
47
     * @return object
48
     */
49
    abstract protected function arrayToEntry(array $entry);
50
51
    /**
52
     * List of entry fields to be indexed and searched.
53
     * May be override in child classes to search by indexed fields.
54
     *
55
     * @return array
56
     */
57
    protected function getIndexDefinition()
58
    {
59
        return [];
60
    }
61
62
    /**
63
     * @return string
64
     */
65
    private function getDatabaseFilePath()
66
    {
67
        return __DIR__ . self::DATABASE_PATH . '/iso_' . $this->getISONumber() . '.json';
68
    }
69
70
    /**
71
     * @return string
72
     */
73
    private function getLocalMessagesPath()
74
    {
75
        return __DIR__ . self::MESSAGES_PATH;
76
    }
77
78
    /**
79
     * @param string $databaseFile
80
     */
81
    private function loadDatabase($databaseFile)
82
    {
83
        // add gettext domain
84
        bindtextdomain(
85
            $this->getISONumber(),
86
            $this->getLocalMessagesPath()
87
        );
88
89
        bind_textdomain_codeset(
90
            $this->getISONumber(),
91
            'UTF-8'
92
        );
93
94
        // load database from json file
95
        $json = json_decode(
96
            file_get_contents($databaseFile),
97
            true
98
        );
99
100
        // build index from database
101
        $entryList = $json[$this->getISONumber()];
102
103
        // index database
104
        $indexedFields = $this->getIndexDefinition();
105
106
        if (empty($indexedFields)) {
107
            $this->clusterIndex = $entryList;
108
        } else {
109
            // init all defined indexes
110
            foreach ($entryList as &$entry) {
111
                foreach ($indexedFields as $indexName => $indexDefinition) {
112
                    if (is_array($indexDefinition)) {
113
                        $reference = &$this->index[$indexName];
114
                        // compound index
115
                        foreach ($indexDefinition as $indexDefinitionPart) {
116
                            // limited length of field
117
                            if (is_array($indexDefinitionPart)) {
118
                                $indexDefinitionPartValue = substr(
119
                                    $entry[$indexDefinitionPart[0]],
120
                                    0,
121
                                    $indexDefinitionPart[1]
122
                                );
123
                            } else {
124
                                $indexDefinitionPartValue = $entry[$indexDefinitionPart];
125
                            }
126
                            if (!isset($reference[$indexDefinitionPartValue])) {
127
                                $reference[$indexDefinitionPartValue] = [];
128
                            }
129
                            $reference = &$reference[$indexDefinitionPartValue];
130
                        }
131
132
                        $reference = $this->arrayToEntry($entry);
133
                    } else {
134
                        // single index
135
                        $indexName = $indexDefinition;
136
                        // skip empty field
137
                        if (empty($entry[$indexDefinition])) {
138
                            continue;
139
                        }
140
                        // add to index
141
                        $this->index[$indexName][$entry[$indexDefinition]] = $this->arrayToEntry($entry);
142
                    }
143
                }
144
            }
145
146
            // set cluster index as first index
147
            $clusterIndexName = key($this->index);
148
            $this->clusterIndex = &$this->index[$clusterIndexName];
149
        }
150
    }
151
152
    /**
153
     * @param string $indexedFieldName
154
     * @param string|int $fieldValue
155
     *
156
     * @return object|null
157
     */
158
    protected function find($indexedFieldName, $fieldValue)
159
    {
160
        if (!isset($this->index[$indexedFieldName][$fieldValue])) {
161
            throw new \InvalidArgumentException(sprintf('Unknown field %s', $indexedFieldName));
162
        }
163
164
        $result = $this->index[$indexedFieldName][$fieldValue];
165
166
        return $result;
167
    }
168
169
    /**
170
     * @return object[]
171
     */
172
    public function toArray()
173
    {
174
        return iterator_to_array($this);
175
    }
176
177
    /**
178
     * @return object
179
     */
180
    public function current()
181
    {
182
        return current($this->clusterIndex);
183
    }
184
185
    /**
186
     * @return int|null
187
     */
188
    public function key()
189
    {
190
        return key($this->clusterIndex);
191
    }
192
193
    public function next()
194
    {
195
        next($this->clusterIndex);
196
    }
197
    
198
    public function rewind()
199
    {
200
        reset($this->clusterIndex);
201
    }
202
203
    /**
204
     * @return bool
205
     */
206
    public function valid()
207
    {
208
        return $this->key() !== null;
209
    }
210
211
    /**
212
     * @return int
213
     */
214
    public function count()
215
    {
216
        return count($this->clusterIndex);
217
    }
218
}
219