1<?php
2
3
4namespace ComboStrap;
5
6
7use ArrayAccess;
8use ArrayObject;
9use Countable;
10
11/**
12 * Class ArrayCaseInsensitive
13 * @package ComboStrap
14 *
15 * Wrapper around an array to make it case access insensitive
16 */
17class ArrayCaseInsensitive implements ArrayAccess, \Iterator, Countable
18{
19
20    /**
21     * A mapping between lower key and original key (ie offset)
22     * @var array
23     */
24    private array $_keyMapping = array();
25    /**
26     * @var array
27     */
28    private array $sourceArray;
29    /**
30     * @var false|mixed
31     */
32    private $valid;
33    private int $iteratorIndex = 0;
34    /**
35     * @var \ArrayIterator
36     */
37    private \ArrayIterator $iterator;
38
39
40    public function __construct(array &$source = array())
41    {
42        $this->sourceArray = &$source;
43        array_walk($source, function ($value, $key) {
44            $this->_keyMapping[strtolower($key)] = $key;
45        });
46
47        /**
48         * Iterator
49         */
50        $this->rewind();
51    }
52
53    public function offsetSet($offset, $value): void
54    {
55
56        if (is_null($offset)) {
57            LogUtility::msg("The offset (key) is null and this is not supported");
58        } else {
59            if (is_string($offset)) {
60                $lowerCaseOffset = strtolower($offset);
61                $this->_keyMapping[$lowerCaseOffset] = $offset;
62                $this->sourceArray[$offset] = $value;
63            } else {
64                LogUtility::msg("The offset should be a string", LogUtility::LVL_MSG_ERROR);
65            }
66
67        }
68    }
69
70    public function offsetExists($offset): bool
71    {
72        if (is_string($offset)) $offset = strtolower($offset);
73        return isset($this->_keyMapping[$offset]);
74    }
75
76    public function offsetUnset($offset): void
77    {
78
79        if (is_string($offset)) $offset = strtolower($offset);
80        $originalOffset = $this->_keyMapping[$offset] ?? null;
81        unset($this->sourceArray[$originalOffset]);
82        unset($this->_keyMapping[$offset]);
83
84    }
85
86
87    public function offsetGet($offset)
88    {
89        if (is_string($offset)) $offset = strtolower($offset);
90        $sourceOffset = $this->_keyMapping[$offset] ?? null;
91        if ($sourceOffset === null) {
92            return null;
93        }
94        return $this->sourceArray[$sourceOffset] ?? null;
95    }
96
97    function getOriginalArray(): array
98    {
99        return $this->sourceArray;
100    }
101
102
103    public function current()
104    {
105        return $this->iterator->current();
106    }
107
108    public function next(): void
109    {
110        $this->iterator->next();
111    }
112
113    public function key()
114    {
115        return $this->iterator->key();
116    }
117
118    public function valid(): bool
119    {
120        return $this->iterator->valid();
121    }
122
123    public function rewind(): void
124    {
125        $obj = new ArrayObject($this->sourceArray);
126        $this->iterator = $obj->getIterator();
127    }
128
129    public function count(): int
130    {
131        return sizeof($this->sourceArray);
132    }
133}
134