Test Failed
Push — 1.0.0-dev ( 76319a...aa9039 )
by nguereza
02:25
created

Model::insertMultiple()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
    defined('ROOT_PATH') || exit('Access denied');
3
    /**
4
     * TNH Framework
5
     *
6
     * A simple PHP framework using HMVC architecture
7
     *
8
     * This content is released under the MIT License (MIT)
9
     *
10
     * Copyright (c) 2017 TNH Framework
11
     *
12
     * Permission is hereby granted, free of charge, to any person obtaining a copy
13
     * of this software and associated documentation files (the "Software"), to deal
14
     * in the Software without restriction, including without limitation the rights
15
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
     * copies of the Software, and to permit persons to whom the Software is
17
     * furnished to do so, subject to the following conditions:
18
     *
19
     * The above copyright notice and this permission notice shall be included in all
20
     * copies or substantial portions of the Software.
21
     *
22
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
     * SOFTWARE.
29
     */
30
31
    class Model {
32
33
       /**
34
         * This model's default database table. 
35
         * @var string the name of table
36
         */
37
        protected $table = '';
38
39
        /**
40
         * The database connection object. Will be set to the default
41
         * connection. This allows individual models to use different DBs
42
         * without overwriting the global database connection.
43
         */
44
        protected $db = null;
45
46
        /**
47
         * This model's default primary key or unique identifier.
48
         * Used by the getSingleRecord(), update() and delete() functions.
49
         */
50
        protected $primaryKey = 'id';
51
52
        /**
53
         * Support for soft deletes and this model's 'deleted' key
54
         * Whether soft delete is enabled or not
55
         * @var boolean
56
         */
57
        protected $softDeleteStatus = false;
58
59
        /**
60
         * Soft delete table column name to use
61
         * @var string
62
         */
63
        protected $softDeleteTableColumn = 'is_deleted';
64
65
        /**
66
         * Whether to return the records with the deleted
67
         * @var boolean
68
         */
69
        protected $returnRecordWithDeleted = false;
70
71
        /**
72
         * Whether to return only the deleted records
73
         * @var boolean
74
         */
75
        protected $returnOnlyRecordDeleted = false;
76
77
        /**
78
         * The various callbacks available to the model. Each are
79
         * simple lists of method names (methods will be call on $this->xxx).
80
         */
81
        protected $beforeCreateCallbacks = array();
82
        protected $afterCreateCallbacks = array();
83
        protected $beforeUpdateCallbacks = array();
84
        protected $afterUpdateCallbacks = array();
85
        protected $beforeGetCallbacks = array();
86
        protected $afterGetCallbacks = array();
87
        protected $beforeDeleteCallbacks = array();
88
        protected $afterDeleteCallbacks = array();
89
90
        /**
91
         * List of methods parameters to use in model callbacks
92
         * @var array
93
         */
94
        protected $callbackParameters = array();
95
96
        /**
97
         * Protected, non-modifiable tables columns
98
         * @var array the list of table attributes that can not be inserted 
99
         * or updated
100
         */
101
        protected $protectedTableColumns = array();
102
103
        /**
104
         * Relationship arrays. Use flat strings for defaults or 
105
         * string => array to customise the class name and primary key
106
         *
107
         * @example 
108
         *  For flat string:
109
         *  $manyToOne = array('relation_name')
110
         *
111
         *  For array:
112
         * $manyToOne = array('relation_name' => array(
113
         *  'primary_key' => 'pk_value',
114
         *  'modek' => 'model_name'
115
         * ))
116
         */
117
        protected $manyToOne = array();
118
        protected $oneToMany = array();
119
120
        /**
121
         * List of relation to return with the fetched record
122
         * @var array
123
         */
124
        protected $withs = array();
125
126
        /**
127
         * An array of validation rules. This needs to be the same format
128
         * as validation rules passed to the FormValidation::setRules library.
129
         */
130
        protected $validationRules = array();
131
132
        /**
133
         * Optionally skip the rules validation. Used in conjunction with
134
         * setSkipRulesValidation() to skip data validation for any future calls.
135
         */
136
        protected $skipRulesValidation = false;
137
138
        /**
139
         * By default we return our results as objects. If we need to override
140
         * this, we can, or, we could use the `asArray()` and `asObject()` scopes.
141
         */
142
        protected $returnRecordType = 'object';
143
144
        /**
145
         * Set return type array or object
146
         * @var string
147
         */
148
        protected $temporaryReturnRecordType = null;
149
    	
150
    	
151
        /**
152
         * The database cache time to live
153
         * The value is in second 
154
         * @example $dbCacheTimeToLive = 300; //so means 5 minutes
155
         *  for the cache to live
156
         *
157
         * @var integer 
158
         */
159
        protected $dbCacheTimeToLive = 0;
160
161
        /**
162
         * Initialise the model.
163
         *
164
         * @param object $db the Database instance to use
165
         * NOTE: each model need use different database instance 
166
         * for cache feature to work, so need use "clone" instead of use the global database 
167
         * instance directly.
168
         */
169
        public function __construct(Database $db = null) {
170
            //Note: don't use the property direct access here as 
171
            //some update is done in the method
172
            //$this->setDb()
173
            if ($db !== null) {
174
                $this->setDb($db);
175
            } else {
176
                 /**
177
                 * NOTE: Need use "clone" because some Model need have the personal instance of the database library
178
                 * to prevent duplication
179
                 */
180
                $obj = & get_instance();
181
                 $this->setDb(clone $obj->database);
182
/*                $obj = & get_instance();
183
                if (isset($obj->database)){
184
                   
185
                    $instance = clone $obj->database;*/
186
            }
187
            array_unshift($this->beforeCreateCallbacks, 'removeProtectedTableColumns');
188
            array_unshift($this->beforeUpdateCallbacks, 'removeProtectedTableColumns');
189
            $this->temporaryReturnRecordType = $this->returnRecordType;
190
        }
191
192
        /**
193
         * Fetch a single record based on the primary key. Returns an object.
194
         *
195
         * @param mixed $pk the primary keys to get record for
196
         *
197
         * @return array|object
198
         */
199
        public function getSingleRecord($pk) {
200
            return $this->getSingleRecordCond($this->primaryKey, $pk);
201
        }
202
203
204
        /**
205
         * Fetch a single record based on an arbitrary WHERE call. Can be
206
         * any valid value to DatabaseQueryBuilder->where().
207
         *
208
         * @return array|object
209
         */
210
        public function getSingleRecordCond() {
211
            $where = func_get_args();
212
            $this->checkForSoftDelete();
213
            $this->setWhereValues($where);
214
            $this->trigger('beforeGetCallbacks');
215
            $type = $this->getReturnType();
216
            $this->getQueryBuilder()->from($this->table);
217
            $row = $this->db->get($type);
218
            $row = $this->trigger('afterGetCallbacks', $row);
219
            $this->temporaryReturnRecordType = $this->returnRecordType;
220
            $this->withs = array();
221
            return $row;
222
        }
223
224
        /**
225
         * Fetch all the records in the table. Can be used as a generic call
226
         * to $this->db->get() with scoped methods.
227
         *
228
         * @param array $pks the list of primary keys if not empty to get record
229
         *
230
         * @return array|object
231
         */
232
        public function getListRecord(array $pks = array()) {
233
            $this->trigger('beforeGetCallbacks');
234
            $this->checkForSoftDelete();
235
            if (!empty($pks)) {
236
                $this->getQueryBuilder()->in($this->primaryKey, $pks);
237
            }
238
            $type = $this->getReturnType();
239
            $this->getQueryBuilder()->from($this->table);
240
            $result = $this->db->getAll($type);
241
            foreach ($result as $key => &$row) {
242
                $row = $this->trigger('afterGetCallbacks', $row, ($key == count($result) - 1));
243
            }
244
            $this->temporaryReturnRecordType = $this->returnRecordType;
245
            $this->withs = array();
246
            return $result;
247
        }
248
249
        /**
250
         * Fetch an array of records based on an arbitrary WHERE call.
251
         *
252
         * @return array|object
253
         */
254
        public function getListRecordCond() {
255
            $where = func_get_args();
256
            $this->setWhereValues($where);
257
            return $this->getListRecord();
258
        }
259
260
        /**
261
         * Insert a new row into the table. $data should be an associative array
262
         * of data to be inserted. Returns newly created ID.
263
         *
264
         * @param array $data the data to be inserted
265
         * @param boolean $skipRulesValidation whether to skip rules validation or not
266
         * @param boolean $escape whether to escape all data values
267
         *
268
         * @return mixed the insert id if the table have auto increment or sequence id field
269
         */
270
        public function insert(array $data = array(), $skipRulesValidation = false, $escape = true) {
271
            if ($this->validateData($data, $skipRulesValidation) !== false) {
272
                $data = $this->trigger('beforeCreateCallbacks', $data);
273
                $this->getQueryBuilder()->from($this->table);
274
                $this->db->insert($data, $escape);
275
                $insertId = $this->db->insertId();
276
                $this->trigger('afterCreateCallbacks', $insertId);
277
                //if the table doesn't have the auto increment field 
278
                //or sequence, the value of 0 will be returned 
279
                if (!$insertId) {
280
                    $insertId = true;
281
                }
282
                return $insertId;
283
            } 
284
            return false;
285
        }
286
287
        /**
288
         * Insert multiple rows into the table.
289
         *
290
         * @param array $data the data to be inserted
291
         * @param boolean $skipRulesValidation whether to skip rules validation or not
292
         * @param boolean $escape whether to escape all data values
293
         *
294
         * @return mixed the array of insert id if the table have auto increment or sequence id field
295
         */
296
        public function insertMultiple(array $data = array(), $skipRulesValidation = false, $escape = true) {
297
            $ids = array();
298
            foreach ($data as $key => $row) {
299
                $ids[] = $this->insert($row, $skipRulesValidation, $escape);
300
            }
301
            return $ids;
302
        }
303
304
        /**
305
         * Updated a record based on the primary key value.
306
         *
307
         * @param mixed $pk the value of primary key to use to do update
308
         * @param array $data the data to be inserted
309
         * @param boolean $skipRulesValidation whether to skip rules validation or not
310
         * @param boolean $escape whether to escape all data values
311
         *
312
         * @return boolean the status of the operation
313
         */
314
        public function update($pk, array $data = array(), $skipRulesValidation = false, $escape = true) {
315
            $data = $this->trigger('beforeUpdateCallbacks', $data);
316
            if ($this->validateData($data, $skipRulesValidation) !== false) {
317
                $this->getQueryBuilder()->where($this->primaryKey, $pk)
318
                                        ->from($this->table);
319
                $result = $this->db->update($data, $escape);
320
                $this->trigger('afterUpdateCallbacks', array($data, $result));
321
                return $result;
322
            } 
323
            return false;
324
        }
325
326
        /**
327
         * Update many records, based on an array of primary keys values.
328
         * 
329
         * @param array $pks the array value of primary keys to do update
330
         * @param array $data the data to be inserted
331
         * @param boolean $skipRulesValidation whether to skip rules validation or not
332
         * @param boolean $escape whether to escape all data values
333
         *
334
         * @return boolean the status of the operation
335
         */
336
        public function updateMultiple($pks, array $data = array(), $skipRulesValidation = false, $escape = true) {
337
            $data = $this->trigger('beforeUpdateCallbacks', $data);
338
            if ($this->validateData($data, $skipRulesValidation) !== false) {
339
                $this->getQueryBuilder()->in($this->primaryKey, $pks)
340
                                        ->from($this->table);
341
                $result = $this->db->update($data, $escape);
342
                $this->trigger('afterUpdateCallbacks', array($data, $result));
343
                return $result;
344
            }
345
            return false;
346
        }
347
348
        /**
349
         * Updated a record based on an arbitrary WHERE clause.
350
         *
351
         * @return boolean the status of the operation
352
         */
353
        public function updateCond() {
354
            $args = func_get_args();
355
            $data = array();
356
            if (count($args) == 2 && is_array($args[1])) {
357
                $data = array_pop($args);
358
            } else if (count($args) == 3 && is_array($args[2])) {
359
                $data = array_pop($args);
360
            }
361
            $data = $this->trigger('beforeUpdateCallbacks', $data);
362
            if ($this->validateRules($data) !== false) {
0 ignored issues
show
introduced by
The condition $this->validateRules($data) !== false is always true.
Loading history...
363
                $this->setWhereValues($args);
364
                $this->getQueryBuilder()->from($this->table);
365
                $result = $this->db->update($data);
366
                $this->trigger('afterUpdateCallbacks', array($data, $result));
367
                return $result;
368
            }
369
            return false;
370
        }
371
372
        /**
373
         * Update all records in the database without conditions
374
         * 
375
         * @param array $data the data to be inserted
376
         * @param boolean $escape whether to escape all data values
377
         *
378
         * @return boolean the status of the operation
379
         */
380
        public function updateAllRecord(array $data = array(), $escape = true) {
381
            $data = $this->trigger('beforeUpdateCallbacks', $data);
382
            $this->getQueryBuilder()->from($this->table);
383
            $result = $this->db->update($data, $escape);
384
            $this->trigger('afterUpdateCallbacks', array($data, $result));
385
            return $result;
386
        }
387
388
        /**
389
         * Delete a row from the table by the primary value
390
         * @param array $id the value of primary key to do delete
391
         * 
392
         * @return boolean the status of the operation
393
         */
394
        public function delete($id) {
395
            $this->trigger('beforeDeleteCallbacks', $id);
396
            $this->getQueryBuilder()->where($this->primaryKey, $id);
397
            $this->getQueryBuilder()->from($this->table);  
398
            $result = $this->deleteRecords();
399
            $this->trigger('afterDeleteCallbacks', $result);
400
            return $result;
401
        }
402
403
        /**
404
         * Delete a row from the database table by an arbitrary WHERE clause
405
         * 
406
         * @return boolean the status of the operation
407
         */
408
        public function deleteCond() {
409
            $where = func_get_args();
410
            $where = $this->trigger('beforeDeleteCallbacks', $where);
411
            $this->setWhereValues($where);
412
            $this->getQueryBuilder()->from($this->table);  
413
            $result = $this->deleteRecords();
414
            $this->trigger('afterDeleteCallbacks', $result);
415
            return $result;
416
        }
417
418
        /**
419
         * Delete many rows from the database table by multiple primary values
420
         * 
421
         * @param array $pks the array value of primary keys to do delete
422
         *
423
         * @return boolean the status of the operation
424
         */
425
        public function deleteListRecord(array $pks) {
426
            $pks = $this->trigger('beforeDeleteCallbacks', $pks);
427
            $this->getQueryBuilder()->in($this->primaryKey, $pks);
428
            $this->getQueryBuilder()->from($this->table);  
429
            $result = $this->deleteRecords();
430
            $this->trigger('afterDeleteCallbacks', $result);
431
            return $result;
432
        }
433
434
        /**
435
         * Truncates the table
436
         *
437
         * @return boolean the truncate status
438
         */
439
        public function truncate() {
440
            $this->getQueryBuilder()->from($this->table); 
441
            $result = $this->db->delete();
442
            return $result;
443
        }
444
445
        /**
446
         * Return the record with the relation
447
         * @param  string $relationship the name of relation to fetch record
448
         * @return object               the current instance
449
         */
450
        public function with($relationship) {
451
            $this->withs[] = $relationship;
452
            if (!in_array('relate', $this->afterGetCallbacks)) {
453
                $this->afterGetCallbacks[] = 'relate';
454
            }
455
            return $this;
456
        }
457
		
458
        /**
459
         * Relationship
460
         * @param array|object $row the row to add relation data into
461
         *
462
         * @return array|object the final row after add relation data
463
         */
464
        protected function relate($row) {
465
            if (empty($row)) {
466
                return $row;
467
            }
468
            $row = $this->relateManyToOne($row);
469
            $row = $this->relateOneToMany($row);
470
            return $row;
471
        }
472
473
        /**
474
         * Retrieve and generate a data to use directly in Form::select()
475
         *
476
         * @return array
477
         */
478
        public function dropdown() {
479
            $args = func_get_args();
480
            if (count($args) == 2) {
481
                list($key, $value) = $args;
482
            } else {
483
                $key = $this->primaryKey;
484
                $value = $args[0];
485
            }
486
            $this->trigger('before_dropdown', array($key, $value));
487
            $this->checkForSoftDelete();
488
            $this->getQueryBuilder()->select(array($key, $value))
489
                                    ->from($this->table);
490
            $result = $this->db->getAll();
491
            $options = array();
492
            foreach ($result as $row) {
493
                $options[$row->{$key}] = $row->{$value};
494
            }
495
            $options = $this->trigger('after_dropdown', $options);
496
            return $options;
497
        }
498
499
        /**
500
         * Fetch a total count of rows, disregarding any previous conditions
501
         * 
502
         * @return integer the number of rows
503
         */
504
        public function countAllRecord() {
505
            $this->checkForSoftDelete();
506
            $this->getQueryBuilder()->from($this->table);
507
            $this->db->getAll();
508
            return $this->db->numRows();
509
        }
510
        
511
        /**
512
         * Fetch a count of rows based on an arbitrary WHERE call.
513
         *
514
         * @return integer the number of rows
515
         */
516
        public function countCond() {
517
            $where = func_get_args();
518
            $this->checkForSoftDelete();
519
            $this->setWhereValues($where);
520
            $this->getQueryBuilder()->from($this->table);
521
            $this->db->getAll();
522
            return $this->db->numRows();
523
        }
524
        
525
        /**
526
         * Enabled cache temporary. This method is the shortcut to Database::cached
527
         *
528
         * @param integer $ttl the cache default time to live
529
         *
530
         * @return object the current instance
531
         */
532
        public function cached($ttl = 0) {
533
            $this->db = $this->db->cached($ttl);
534
            return $this;
535
        }
536
537
        /**
538
         * Tell the class to skip the data validation
539
         * @param boolean $status the status of rules validation
540
         *
541
         * @return object the current instance
542
         */
543
        public function setSkipRulesValidation($status = true) {
544
            $this->skipRulesValidation = $status;
545
            return $this;
546
        }
547
548
        /**
549
         * Get the skip validation status
550
         *
551
         * @return boolean
552
         */
553
        public function isSkipRulesValidation() {
554
            return $this->skipRulesValidation;
555
        }
556
557
        /**
558
         * Return the next auto increment of the table. 
559
         * Only tested on MySQL and SQLite
560
         *
561
         * @return mixed
562
         */
563
        public function getNextAutoIncrementId() {
564
            $driver = $this->db->getConnection()->getDriver();
565
            if ($driver == 'mysql') {
566
                $this->getQueryBuilder()->select('AUTO_INCREMENT')
567
                                        ->from('information_schema.TABLES')
568
                                        ->where('TABLE_NAME', $this->getTable())
569
                                        ->where('TABLE_SCHEMA', $this->db->getConnection()->getDatabase());
570
                return (int) $this->db->get()->AUTO_INCREMENT;
571
            }
572
573
            if ($driver == 'sqlite') {
574
                $this->getQueryBuilder()->select('SEQ')
575
                                        ->from('SQLITE_SEQUENCE')
576
                                        ->where('NAME', $this->getTable());
577
                return ((int) $this->db->get()->seq) + 1;
578
            }
579
            return null;
580
        }
581
582
        /**
583
         * Getter for the table name
584
         *
585
         * @return string the name of table
586
         */
587
        public function getTable() {
588
            return $this->table;
589
        }
590
591
        /**
592
         * Getter for the primary key name
593
         *
594
         * @return string the name of primary key
595
         */
596
        public function getPrimaryKey() {
597
            return $this->primaryKey;
598
        }
599
600
        /**
601
         * Return the next call as an array rather than an object
602
         */
603
        public function asArray() {
604
            $this->temporaryReturnRecordType = 'array';
605
            return $this;
606
        }
607
608
        /**
609
         * Return the next call as an object rather than an array
610
         */
611
        public function asObject() {
612
            $this->temporaryReturnRecordType = 'object';
613
            return $this;
614
        }
615
616
        /**
617
         * Don't care about soft deleted rows on the next call
618
         *
619
         * @return object the current instance
620
         */
621
        public function recordWithDeleted() {
622
            $this->returnRecordWithDeleted = true;
623
            return $this;
624
        }
625
626
        /**
627
         * Only get deleted rows on the next call
628
         * 
629
         * @return object the current instance
630
        */
631
        public function onlyRecordDeleted() {
632
            $this->returnOnlyRecordDeleted = true;
633
            return $this;
634
        }
635
636
        /**
637
         * Table DATETIME field created_at
638
         *
639
         * @param array $row the data to be inserted
640
         *
641
         * @return array the data after add field for created time
642
         */
643
        public function createdAt($row) {
644
            $row['created_at'] = date('Y-m-d H:i:s');
645
            return $row;
646
        }
647
648
        /**
649
         * Table DATETIME field  updated_at
650
         *
651
         * @param array $row the data to be updated
652
         *
653
         * @return array the data after add field for updated time
654
         */
655
        public function updatedAt($row) {
656
           $row['updated_at'] = date('Y-m-d H:i:s');
657
           return $row;
658
        }
659
660
        /**
661
         * Serialises data for you automatically, allowing you to pass
662
         * through objects and let it handle the serialisation in the background
663
         *
664
         * @param array|object $row the data to be serialized
665
         * 
666
         * @return array|object the data after processing
667
         */
668
        public function serialize($row) {
669
            foreach ($this->callbackParameters as $column) {
670
                $row[$column] = serialize($row[$column]);
671
            }
672
            return $row;
673
        }
674
675
        /**
676
         * Unserialises data for you automatically, allowing you to pass
677
         * through objects and let it handle the serialisation in the background
678
         *
679
         * @param array|object $row the data to be unserialized
680
         * 
681
         * @return array|object the data after processing
682
         */
683
        public function unserialize($row) {
684
            foreach ($this->callbackParameters as $column) {
685
                if (is_array($row)) {
686
                    $row[$column] = unserialize($row[$column]);
687
                } else {
688
                    $row->$column = unserialize($row->$column);
689
                }
690
            }
691
            return $row;
692
        }
693
694
        /**
695
         * Protect attributes by removing them from data to insert or update
696
         *
697
         * @return mixed the final row after remove the protected
698
         * table columns if they exist
699
         */
700
        public function removeProtectedTableColumns($row) {
701
            foreach ($this->protectedTableColumns as $attr) {
702
               if (isset($row[$attr])) {
703
                    unset($row[$attr]);
704
                }
705
            }
706
            return $row;
707
        }
708
		
709
        /**
710
         * Return the database instance
711
         * @return Database the database instance
712
         */
713
        public function getDb() {
714
            return $this->db;
715
        }
716
717
        /**
718
         * Set the Database instance for future use
719
         * @param Database $db the database object
720
         */
721
        public function setDb(Database $db) {
722
            $this->db = $db;
723
            if ($this->dbCacheTimeToLive > 0) {
724
                $this->db->setCacheTimeToLive($this->dbCacheTimeToLive);
725
            }
726
            return $this;
727
        }
728
729
        /**
730
         * Return the queryBuilder instance this is the shortcut to database queryBuilder
731
         * @return object the DatabaseQueryBuilder instance
732
         */
733
        public function getQueryBuilder() {
734
            return $this->db->getQueryBuilder();
735
        }
736
737
        /**
738
         * Set the DatabaseQueryBuilder instance for future use
739
         * @param object $queryBuilder the DatabaseQueryBuilder object
740
         * @return object
741
         */
742
        public function setQueryBuilder($queryBuilder) {
743
            $this->db->setQueryBuilder($queryBuilder);
744
            return $this;
745
        }
746
747
        /* --------------------------------------------------------------
748
         * QUERY BUILDER DIRECT ACCESS METHODS
749
         * ------------------------------------------------------------ */
750
751
        /**
752
         * A wrapper to $this->getQueryBuilder()->orderBy()
753
         *
754
         * @see  DatabaseQueryBuilder::orderBy
755
         */
756
        public function orderBy($criteria, $order = 'ASC') {
757
            if (is_array($criteria)) {
758
                foreach ($criteria as $key => $value) {
759
                    $this->getQueryBuilder()->orderBy($key, $value);
760
                }
761
            } else {
762
                $this->getQueryBuilder()->orderBy($criteria, $order);
763
            }
764
            return $this;
765
        }
766
767
        /**
768
         * A wrapper to $this->getQueryBuilder()->limit()
769
         * 
770
         * @see  DatabaseQueryBuilder::limit
771
         */
772
        public function limit($offset = 0, $limit = 10) {
773
            $this->getQueryBuilder()->limit($offset, $limit);
774
            return $this;
775
        }
776
777
        /**
778
         * Delete record in tha database
779
         * 
780
         * @return boolean the delete status
781
         */
782
        protected function deleteRecords() {
783
            $result = false;
784
            if ($this->softDeleteStatus) {
785
                $result = $this->db->update(array($this->softDeleteTableColumn => 1));
786
            } else {
787
                $result = $this->db->delete();
788
            }
789
            return $result;
790
        }
791
792
        /**
793
         * Validate the data using the validation rules
794
         * 
795
         * @param  array $data the data to validate before insert, update, etc.
796
         * @param boolean $skipValidation whether to skip validation or not
797
         * 
798
         * @return array|boolean
799
         */
800
        protected function validateData($data, $skipValidation) {
801
            if ($skipValidation === false) {
802
                $data = $this->validateRules($data);
803
            }
804
            return $data;
805
        }
806
807
        /**
808
         * Run validation on the passed data
809
         * @param  array $data the data to validate before insert, update, etc.
810
         * 
811
         * @return array|boolean 
812
         */
813
        protected function validateRules(array $data) {
814
            if ($this->isSkipRulesValidation() || empty($this->validationRules)) {
815
                return $data;
816
            }
817
            get_instance()->formvalidation->setData($data);
818
            get_instance()->formvalidation->setRules($this->validationRules);
819
            if (get_instance()->formvalidation->validate() === true) {
820
                return $data;
821
            }
822
            return false;
823
        }
824
825
         /**
826
         * Get the record return type array or object
827
         * 
828
         * @return string|boolean
829
         */
830
        protected function getReturnType(){
831
            $type = false;
832
            if ($this->temporaryReturnRecordType == 'array') {
833
               $type = 'array';
834
            }
835
            return $type;
836
        }
837
838
         /**
839
         * Check if soft delete is enable setting the condition
840
         * @return object the current instance 
841
         */
842
        protected function checkForSoftDelete(){
843
            if ($this->softDeleteStatus && $this->returnRecordWithDeleted !== true) {
844
                $this->getQueryBuilder()->where(
845
                                                $this->softDeleteTableColumn, 
846
                                                (int) $this->returnOnlyRecordDeleted
847
                                            );
848
            }
849
            return $this;
850
        }
851
852
         /**
853
         * Relate for "manyToOne" and "oneToMany"
854
         * 
855
         * @param  string $relationship the name of relation
856
         * @param  string|array $options      the model and primary key values
857
         * @param  object|array $row          the row to update
858
         * @param  string $type the type can be "manyToOne", "oneToMany"
859
         * 
860
         * @return array|object the final row values
861
         */
862
        protected function relateOneToManyAndManyToOne($relationship, $options, $row, $type){
863
            if (in_array($relationship, $this->withs)) {
864
                get_instance()->loader->model($options['model'], $relationship . '_model');
865
                $model = get_instance()->{$relationship . '_model'};
866
                if($type == 'manyToOne'){
867
                    if (is_object($row)) {
868
                        $row->{$relationship} = $model->getSingleRecord($row->{$options['primary_key']});
869
                    } else {
870
                        $row[$relationship] = $model->getSingleRecord($row[$options['primary_key']]);
871
                    }
872
                } else {
873
                    if (is_object($row)) {
874
                        $row->{$relationship} = $model->getListRecordCond($options['primary_key'], $row->{$this->primaryKey});
875
                    } else {
876
                        $row[$relationship] = $model->getListRecordCond($options['primary_key'], $row[$this->primaryKey]);
877
                    }
878
                }
879
            }
880
            return $row;
881
        }
882
883
        /**
884
         * Relate for the relation "manyToOne"
885
         * @see Model::relateOneToManyAndManyToOne
886
         */
887
        protected function relateManyToOne($row) {
888
            foreach ($this->manyToOne as $key => $value) {
889
                $options = $this->getRelationshipOptions($key, $value);
890
                $row = $this->relateOneToManyAndManyToOne(
891
                                                            $options['relationship'], 
892
                                                            $options, 
893
                                                            $row, 
894
                                                            'manyToOne'
895
                                                        );
896
            }
897
            return $row;
898
        }
899
900
        /**
901
         * Relate for the relation "oneToMany"
902
         * @see Model::relateOneToManyAndManyToOne
903
         */
904
        protected function relateOneToMany($row) {
905
            foreach ($this->oneToMany as $key => $value) {
906
                $options = $this->getRelationshipOptions($key, $value);
907
                $row = $this->relateOneToManyAndManyToOne(
908
                                                            $options['relationship'], 
909
                                                            $options, 
910
                                                            $row, 
911
                                                            'oneToMany'
912
                                                        );
913
            }
914
            return $row;
915
        }
916
917
        /**
918
         * Get the relationship options to use 
919
         * @param  mixed $key   the relationship key
920
         * @param  mixed $value the raltionship value for custom option
921
         * @return array the options
922
         */
923
        protected function getRelationshipOptions($key, $value) {
924
            $relationship = null;
925
            $options = null;
926
            if (is_string($value)) {
927
                $relationship = $value;
928
                $options = array('primary_key' => $this->table . '_id', 'model' => $value . '_model');
929
            } else {
930
                $relationship = $key;
931
                $options = $value;
932
            }
933
            $options['relationship'] = $relationship;
934
            return $options;
935
        }
936
		
937
        /**
938
         * Trigger an event and call its observers. Pass through the event name
939
         * (which looks for an instance variable $this->event_name), an array of
940
         * parameters to pass through and an optional 'last in interation' boolean
941
         *
942
         * @param string $event the name of event like afterGetCallbacks
943
         * @param mixed $data the data to pass to the callback
944
         * @param boolean $last if is the last row of data to process
945
         *
946
         * @return mixed the data after each callbacks processed
947
         */
948
        protected function trigger($event, $data = false, $last = true) {
949
            if (isset($this->$event) && is_array($this->$event)) {
950
                foreach ($this->$event as $method) {
951
                    if (strpos($method, '(')) {
952
                        preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches);
953
                        $method = $matches[1];
954
                        $this->callbackParameters = explode(',', $matches[3]);
955
                    }
956
                    $data = call_user_func_array(array($this, $method), array($data, $last));
957
                }
958
            }
959
            return $data;
960
        }
961
		
962
        /**
963
         * Set WHERE parameters, when is array
964
         * @param array $params
965
         *
966
         * @return object the current instance
967
         */
968
        protected function setWhereValuesArray(array $params) {
969
            foreach ($params as $field => $filter) {
970
                if (is_array($filter)) {
971
                    $this->getQueryBuilder()->in($field, $filter);
972
                } else {
973
                    if (is_int($field)) {
974
                        $this->getQueryBuilder()->where($filter);
975
                    } else {
976
                        $this->getQueryBuilder()->where($field, $filter);
977
                    }
978
                }
979
            }
980
            return $this;
981
        }
982
983
        /**
984
         * Set WHERE parameters, cleverly
985
         * @param mixed $params the parameters of where
986
         * 
987
         * @return object the current instance
988
         */
989
        protected function setWhereValues($params) {
990
            if (count($params) == 1) {
991
                if (is_array($params[0])) {
992
                    $this->setWhereValuesArray($params[0]);
993
                } else {
994
                    $this->getQueryBuilder()->where($params[0]);
995
                }
996
            } else if (count($params) == 2) {
997
                if (is_array($params[1])) {
998
                    $this->getQueryBuilder()->in($params[0], $params[1]);
999
                } else {
1000
                    $this->getQueryBuilder()->where($params[0], $params[1]);
1001
                }
1002
            } else if (count($params) == 3) {
1003
                $this->getQueryBuilder()->where($params[0], $params[1], $params[2]);
1004
            } 
1005
        }
1006
    }
1007