DBCollection::getTableName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use ReflectionClass;
8
use BadMethodCallException;
9
10
class DBCollection extends Collection
11
{
12
    /* @var string SQL table name */
13
    protected $tableName = '';
14
    /* @var string Item type stored in collection */
15
    protected $itemsType = '';
16
    /* @var string Database configuration identifier */
17
    protected $DBConfig = '';
18
19
    protected $mapping = [];
20
    protected $loadedValues = [];
21
    protected $lazyLoad = false;
22
23
    protected $dbLink = false;
24
    protected $itemOffset = 0;
25
26
    /**
27
     * Get table name
28
     *
29
     * @return string
30
     */
31 2
    public function getTableName(): string
32
    {
33 2
        return $this->tableName;
34
    }
35
36 4
    public function getItemsType(): string
37
    {
38 4
        return $this->itemsType;
39
    }
40
41 1
    public function getDBConfig(): string
42
    {
43 1
        return $this->DBConfig;
44
    }
45
46
    /**
47
     * __sleep magic method, permits an inherited DBObject class to be serialized
48
     * @return Array of properties to serialize
49
     */
50
    // FIXME: should be replaced by __serialize in PHP 8.5
51
    public function __sleep()
52
    {
53
        $discardedProps = ['dbLink'];
54
        $reflection = new ReflectionClass($this);
55
        $props = $reflection->getProperties();
56
        $result = [];
57
        foreach ($props as $currentProperty) {
58
            $result[] = $currentProperty->name;
59
        }
60
61
        return array_diff($result, $discardedProps);
62
    }
63
64
    /**
65
     * Wake up magic method
66
     * restore dblink to initial value
67
     */
68
    // FIXME: should be replaced by __unserialize in PHP 8.5
69
    public function __wakeup()
70
    {
71
        $this->dbLink = false;
72
    }
73
74
    /**
75
     * Set lazyload flag
76
     *
77
     * @param bool $lazyLoad
78 1
     * @return DBCollection
79
     */
80 1
    public function setLazyLoad($lazyLoad)
81
    {
82 1
        $this->lazyLoad = $lazyLoad;
83
84
        return $this;
85
    }
86
87
    /**
88
     * Get lazyload flag
89
     *
90 1
     * @return boolean
91
     */
92 1
    public function getLazyLoad(): bool
93
    {
94
        return $this->lazyLoad;
95
    }
96
97
    public function purgeItems()
98
    {
99
        $this->items = [];
100
        $this->mapping = [];
101
        $this->itemOffset = 0;
102
    }
103
104
    /**
105
     * Implementation of ArrayAccess Interface
106
     * override parent get to lazyLoad item
107
     * @param  mixed $offset Offset to get
108 2
     * @return mixed
109
     */
110 2
    public function offsetGet(mixed $offset): mixed
111 2
    {
112
        if (!$this->lazyLoad) {
113
            return parent::offsetGet($offset);
114
        }
115
116
        if (
117
            isset($this->loadedValues[$offset]) &&
118
            $this->loadedValues[$offset]
119
        ) {
120
            return $this->items[$offset];
121
        }
122
123
        $itemType = $this->itemsType;
124
        $itemToLoad = new $itemType();
125
        $itemToLoad->load($this->items[$offset]);
126
127
        $this->items[$offset] = $itemToLoad;
128
        $this->loadedValues[$offset] = true;
129
130
        return $this->items[$offset];
131
    }
132
133
    /**
134
     * Load entire table into collection
135 1
     * @return DBCollection Loaded collection
136
     */
137 1
    public static function loadAll()
138 1
    {
139
        $calledClass = get_called_class();
140 1
        $collection = new $calledClass();
141
142 1
        $sqlParams = [];
143 1
144
        $sql = "SELECT *";
145 1
        $sql .= "   FROM `" . $collection->getTableName() . "`";
146
147 1
        $collection->loadFromSql($sql, $sqlParams);
148
149
        return $collection;
150
    }
151
152
    /**
153
     * Static wrapper for loadFromSql
154
     * @param  string     $sql       SQL Statement
155
     * @param  array      $sqlParams SQL Parameters
156 1
     * @return DBCollection Loaded collection
157
     */
158 1
    public static function buildFromSql($sql, $sqlParams = [])
159 1
    {
160
        $calledClass = get_called_class();
161 1
        $collection = new $calledClass();
162
163 1
        $collection->loadFromSql($sql, $sqlParams);
164
165
        return $collection;
166
    }
167
168
    /**
169
     * Load collection from SQL query
170
     *
171
     * @param string $sql       SQL query
172
     * @param array  $sqlParams associative array of SQL params
173 3
     * @return DBCollection
174
     */
175
    public function loadFromSql($sql, $sqlParams = [])
176 3
    {
177 3
        if (
178 3
            !in_array(
179
                Interfaces\IDBObject::class,
180
                class_implements($this->itemsType)
181
            )
182
        ) {
183
            throw new BadMethodCallException(
184
                'Item type does not implement IDBObject interface'
185
            );
186 3
        }
187 3
188
        $this->connectDB();
189 3
        $results = $this->dbLink->query($sql, $sqlParams)->fetchAll();
190 3
191 3
        if ($results !== false) {
192 3
            foreach ($results as $currentResult) {
193 3
                $itemName = $this->getItemsType();
194 3
                $item = $itemName::instanciate($currentResult);
195
                $item->setLoaded();
196
                $this->addItem($item);
197
            }
198 3
        }
199
200
        return $this;
201
    }
202
203
    protected function addItemLink($linkId)
204
    {
205
        $this->items[$this->itemOffset] = $linkId;
206
        // add mapping between item->index and $position in items pool
207
        $this->mapping[$this->itemOffset] = $linkId;
208
        $this->loadedValues[$this->itemOffset] = false;
209
        $this->itemOffset++;
210
    }
211
212
    public function lazyLoadFromSql($sql, $sqlParams = [])
213
    {
214
        $this->connectDB();
215
        $results = $this->dbLink->query($sql, $sqlParams)->fetchAll();
216
217
        if ($results !== false) {
218
            foreach ($results as $currentResult) {
219
                $this->addItemLink(current($currentResult));
220
            }
221
        }
222
223
        return $this;
224
    }
225
226
    public function craftItem($itemData)
227
    {
228
        $itemName = $this->itemsType;
229
230
        foreach ($itemData as $data) {
231
            $newItem = new $itemName();
232
            $hasData = false;
233
            foreach ($data as $field => $value) {
234
                $newItem->$field = $value;
235
                if ($value != '') {
236
                    $hasData = true;
237
                }
238
            }
239
240
            // Only add item if there's data inside
241
            if ($hasData) {
242
                $this->addItem($newItem);
243
            }
244
        }
245
    }
246
247
    public function save()
248
    {
249
        foreach ($this->items as $currentItem) {
250
            $currentItem->save(true); // Force insert
251
        }
252 3
    }
253
254 3
    public function addItem(Interfaces\IDBObject $item)
255
    {
256 3
        $key = $item->getTableIndex();
257
        // Add item to items pool
258
        $this->items[$this->itemOffset] = $item;
259 3
260
        // add mapping between item->index and $position in items pool
261 3
        $this->mapping[$this->itemOffset] = $item->$key;
262
263 3
        $this->itemOffset++;
264
265
        return $this;
266
    }
267
268
    /**
269
     * Connect to database layer
270
     *
271
     * @return void
272 3
     * @SuppressWarnings("PHPMD.StaticAccess")
273
     */
274 3
    protected function connectDB()
275
    {
276
        // FIXME: potential reuse of connection. If using >= 2 differents DB Config
277
        // the missing `true` in Database() call keeps querying the previously connected DB
278
        // Check if performance issue of passing `true` everytime
279
        if (!$this->dbLink) {
280 3
            $this->dbLink = Suricate::Database();
281
            if ($this->getDBConfig() !== '') {
282
                $this->dbLink->setConfig($this->getDBConfig());
283
            }
284
        }
285
    }
286
}
287