DBCollection::lazyLoadFromSql()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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