Passed
Push — develop ( f7d5f1...b2e8eb )
by Mathieu
01:53
created

DBCollection::loadFromSql()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 2
nop 2
dl 0
loc 13
ccs 8
cts 8
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Suricate;
3
4
class DBCollection extends Collection
5
{
6
    /* @var string SQL table name */
7
    protected $tableName        = '';
8
    /* @var string Item type stored in collection */
9
    protected $itemsType        = '';
10
    /* @var string Database configuration identifier */
11
    protected $DBConfig         = '';
12
    /* @var string Name of parent identifier field */
13
    protected $parentIdField    = 'parent_id';
14
    /** @var string Parent Object type */
15
    protected $parentType       = '';
16
17
    protected $mapping          = [];
18
    protected $lazyLoad = false;
19
    protected $parentId;                       // Id of the parent
20
    protected $parentFilterName;                // Name of field used for filtering
21
    protected $parentFilterType;                // Value of filter
22
23
    protected $dbLink               = false;
24
    protected $itemOffset           = 0;
25
26
    /**
27
     * Get table name
28
     *
29
     * @return string
30
     */
31 1
    public function getTableName(): string
32
    {
33 1
        return $this->tableName;
34
    }
35
36 2
    public function getItemsType(): string
37
    {
38 2
        return $this->itemsType;
39
    }
40
41 1
    public function getDBConfig(): string
42
    {
43 1
        return $this->DBConfig;
44
    }
45
46 1
    public function getParentIdField(): string
47
    {
48 1
        return $this->parentIdField;
49
    }
50
51 1
    public function getParentType()
52
    {
53 1
        return $this->parentType;
54
    }
55
56 1
    public function getParentId()
57
    {
58 1
        return $this->parentId;
59
    }
60
61
    /**
62
     * Set lazyload flag
63
     *
64
     * @param bool $lazyLoad
65
     * @return DBCollection
66
     */
67 1
    public function setLazyLoad($lazyLoad)
68
    {
69 1
        $this->lazyLoad = $lazyLoad;
70
71 1
        return $this;
72
    }
73
74
    /**
75
     * Get lazyload flag
76
     *
77
     * @return boolean
78
     */
79 1
    public function getLazyLoad(): bool
80
    {
81 1
        return $this->lazyLoad;
82
    }
83
84
    public function purgeItems()
85
    {
86
        $this->items        = [];
87
        $this->mapping      = [];
88
        $this->itemOffset   = 0;
89
    }
90
91
    /**
92
     * Load entire table into collection
93
     * @return Collection Loaded collection
94
     */
95
    public static function loadAll()
96
    {
97
        $calledClass    = get_called_class();
98
        $collection     = new $calledClass;
99
100
        $sqlParams      = [];
101
102
        $sql  = "SELECT *";
103
        $sql .= "   FROM `" . $collection::getTableName() . "`";
104
105
        if ($collection->parentFilterType !== '' && $collection->parentFilterType != null) {
106
            $sql .= "WHERE " . $collection->parentFilterName . "=:type";
107
            $sqlParams['type'] = $collection->parentFilterType;
108
        }
109
        $dbLink = Suricate::Database();
0 ignored issues
show
Bug introduced by
The method Database() does not exist on Suricate\Suricate. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

109
        /** @scrutinizer ignore-call */ 
110
        $dbLink = Suricate::Database();
Loading history...
110
        if ($collection->getDBConfig() !== '') {
111
            $dbLink->setConfig($collection->getDBConfig());
112
        }
113
        $results = $dbLink->query($sql, $sqlParams)->fetchAll();
114
115
        if ($results !== false) {
116
            foreach ($results as $currentResult) {
117
                $itemName = $collection->getItemsType();
118
                $collection->addItem($itemName::instanciate($currentResult));
119
            }
120
        }
121
122
        return $collection;
123
    }
124
125
    /**
126
     * Static wrapper for loadFromSql
127
     * @param  string     $sql       SQL Statement
128
     * @param  array      $sqlParams SQL Parameters
129
     * @return Collection Loaded collection
130
     */
131
    public static function buildFromSql($sql, $sqlParams = [])
132
    {
133
        $calledClass = get_called_class();
134
        $collection = new $calledClass;
135
136
        $collection->loadFromSql($sql, $sqlParams);
137
138
        return $collection;
139
    }
140
141
    /**
142
     * Load collection from SQL query
143
     *
144
     * @param string $sql       SQL query
145
     * @param array  $sqlParams associative array of SQL params
146
     * @return DBCollection
147
     */
148 1
    public function loadFromSql($sql, $sqlParams = [])
149
    {
150 1
        $this->connectDB();
151 1
        $results = $this->dbLink->query($sql, $sqlParams)->fetchAll();
152
153 1
        if ($results !== false) {
154 1
            foreach ($results as $currentResult) {
155 1
                $itemName = $this->getItemsType();
156 1
                $this->addItem($itemName::instanciate($currentResult));
157
            }
158
        }
159
160 1
        return $this;
161
    }
162
163
    public function addItemLink($linkId)
164
    {
165
         $this->items[$this->itemOffset] = $linkId;
166
         // add mapping between item->index and $position in items pool
167
         $this->mapping[$this->itemOffset] = $linkId;
168
         $this->itemOffset++;
169
    }
170
171
    public function lazyLoadFromSql($sql, $sqlParams = array())
172
    {
173
        $dbLink = Suricate::Database();
174
        if ($this->DBConfig !== '') {
175
            $dbLink->setConfig($this->DBConfig);
176
        }
177
178
        $results = $dbLink
179
            ->query($sql, $sqlParams)
180
            ->fetchAll();
181
182
        if ($results !== false) {
183
            foreach ($results as $currentResult) {
184
                $this->addItemLink(current($currentResult));
185
            }
186
        }
187
188
        return $this;
189
    }
190
191
    /**
192
     * Load items linked to a parentId
193
     * @param mixed        $parentId       Parent id description
194
     * @param string       $parentIdField  Name of parent id referencing field
195
     * @param \Closure|null $validate       Callback use to validate add to items collection
196
     */
197
    public static function loadForParentId($parentId, $parentIdField = null, $validate = null)
198
    {
199
        $calledClass   = get_called_class();
200
        $collection     = new $calledClass;
201
202
        if ($parentId != '') {
203
            $sqlParams     = [];
204
            $dbHandler     = Suricate::Database(true);
205
206
            if ($collection->getDBConfig() !== '') {
207
                $dbHandler->setConfig($collection->getDBConfig());
208
            }
209
210
            $sql  = "SELECT *";
211
            $sql .= " FROM `" . $collection->getTableName() . "`";
212
            $sql .= " WHERE";
213
            if ($parentIdField !== null) {
214
                $sql .= "`" . $parentIdField . "`=:parent_id";
215
            } else {
216
                $sql .= "`" . $collection->getParentIdField() . "`=:parent_id";
217
            }
218
219
            if ($collection->parentFilterType !== null) {
220
                $sql .= "   AND " . $collection->parentFilterName . "=:parent_type";
221
                $sqlParams['parent_type'] = $collection->parentFilterType;
222
            }
223
224
            $sqlParams['parent_id'] = $parentId;
225
            $results = $dbHandler->query($sql, $sqlParams)->fetchAll();
226
227
            if ($results !== false) {
228
                foreach ($results as $currentResult) {
229
                    $itemName = $collection->getItemsType();
230
                    $item = $itemName::instanciate($currentResult);
231
                    if ($validate === null || $validate($item)) {
232
                        $collection->addItem($item);
233
                    }
234
                }
235
            }
236
237
            $collection->parentId = $parentId;
238
        }
239
240
        return $collection;
241
    }
242
243
    public function setParentIdForAll($parentId)
244
    {
245
        $this->parentId = $parentId;
246
        foreach (array_keys($this->items) as $key) {
247
            $this->items[$key]->{$this->parentIdField} = $parentId;
248
        }
249
    }
250
251
    /**
252
     * Load Parent Item, if item type is defined
253
     */
254
    public function loadParent()
255
    {
256
        if ($this->parentType !== '' && $this->parentId != '') {
257
            $parentObjectType = $this->parentType;
258
            $parent = new $parentObjectType();
259
            if (method_exists($parent, 'load')) {
260
                $parent->load($this->parentId);
261
262
                return $parent;
263
            } else {
264
                throw new \BadMethodCallException('Parent object does not have a load($id) method');
265
            }
266
        } else {
267
            throw new \BadMethodCallException('self::$parentType is not defined');
268
        }
269
    }
270
271
    public function craftItem($itemData)
272
    {
273
        $itemName = $this->itemsType;
274
275
        foreach ($itemData as $data) {
276
            $newItem = new $itemName();
277
            $newItem->{$this->parentIdField} = $this->parentId;
278
            $hasData = false;
279
            foreach ($data as $field => $value) {
280
                $newItem->$field = $value;
281
                if ($value != '') {
282
                    $hasData = true;
283
                }
284
            }
285
286
            // Only add item if there's data inside
287
            if ($hasData) {
288
                $this->addItem($newItem);
289
            }
290
        }
291
    }
292
293
    public function save()
294
    {
295
        // 1st step : delete all records for current parentId
296
        $sql  = "DELETE FROM `" . $this->tableName . "`";
297
        if ($this->parentIdField !== '') {
298
            $sql .= " WHERE";
299
            $sql .= "   `" . $this->parentIdField . "`=:parent_id";
300
301
            $sqlParams = array('parent_id' => $this->parentId);
302
        } else {
303
            $sqlParams = array();
304
        }
305
306
        $dbLink = Suricate::Database();
307
        if ($this->DBConfig !== '') {
308
            $dbLink->setConfig($this->DBConfig);
309
        }
310
        
311
        $dbLink->query($sql, $sqlParams);
312
313
        // 2nd step : save all current items
314
        foreach ($this->items as $currentItem) {
315
            $currentItem->save(true); // Force insert
316
        }
317
    }
318
319 1
    public function addItem(Interfaces\IDBObject $item)
320
    {
321 1
        $key = $item->getTableIndex();
322
        // Add item to items pool
323 1
        $this->items[$this->itemOffset] = $item;
324
325
        // add mapping between item->index and $position in items pool
326 1
        $this->mapping[$this->itemOffset] = $item->$key;
327
328 1
        $this->itemOffset++;
329
330 1
        return $this;
331
    }
332
333 1
    protected function connectDB()
334
    {
335 1
        if (!$this->dbLink) {
336
            $this->dbLink = Suricate::Database();
337
            if ($this->getDBConfig() !== '') {
338
                $this->dbLink->setConfig($this->getDBConfig());
339
            }
340
        }
341 1
    }
342
}
343