Passed
Push — 1.0.0-dev ( 024223...5d8234 )
by nguereza
02:46
created

Model::update_all()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
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
32
    /**
33
     * A base model with a series of CRUD functions (powered by CI's query builder),
34
     * validation-in-model support, event callbacks and more.
35
     *
36
     * @link http://github.com/jamierumbelow/codeigniter-base-model
37
     * @copyright Copyright (c) 2012, Jamie Rumbelow <http://jamierumbelow.net>
38
     */
39
40
    class Model {
41
42
        /* --------------------------------------------------------------
43
         * VARIABLES
44
         * ------------------------------------------------------------ */
45
46
        /**
47
         * This model's default database table. Automatically
48
         * guessed by pluralising the model name.
49
         */
50
        protected $_table;
51
52
        /**
53
         * The database connection object. Will be set to the default
54
         * connection. This allows individual models to use different DBs
55
         * without overwriting the global database connection.
56
         */
57
        protected $_database;
58
59
        /**
60
         * This model's default primary key or unique identifier.
61
         * Used by the get(), update() and delete() functions.
62
         */
63
        protected $primary_key = 'id';
64
65
        /**
66
         * Support for soft deletes and this model's 'deleted' key
67
         */
68
        protected $soft_delete = false;
69
        protected $soft_delete_key = 'is_deleted';
70
        protected $_temporary_with_deleted = FALSE;
71
        protected $_temporary_only_deleted = FALSE;
72
73
        /**
74
         * The various callbacks available to the model. Each are
75
         * simple lists of method names (methods will be run on $this).
76
         */
77
        protected $before_create = array();
78
        protected $after_create = array();
79
        protected $before_update = array();
80
        protected $after_update = array();
81
        protected $before_get = array();
82
        protected $after_get = array();
83
        protected $before_delete = array();
84
        protected $after_delete = array();
85
86
        protected $callback_parameters = array();
87
88
        /**
89
         * Protected, non-modifiable attributes
90
         */
91
        protected $protected_attributes = array();
92
93
        /**
94
         * Relationship arrays. Use flat strings for defaults or string
95
         * => array to customise the class name and primary key
96
         */
97
        protected $belongs_to = array();
98
        protected $has_many = array();
99
100
        protected $_with = array();
101
102
        /**
103
         * An array of validation rules. This needs to be the same format
104
         * as validation rules passed to the FormValidation library.
105
         */
106
        protected $validate = array();
107
108
        /**
109
         * Optionally skip the validation. Used in conjunction with
110
         * skip_validation() to skip data validation for any future calls.
111
         */
112
        protected $skip_validation = FALSE;
113
114
        /**
115
         * By default we return our results as objects. If we need to override
116
         * this, we can, or, we could use the `as_array()` and `as_object()` scopes.
117
         */
118
        protected $return_type = 'object';
119
120
        /**
121
         * Set return type array or object
122
         * @var string
123
         */
124
        protected $_temporary_return_type = NULL;
125
    	
126
    	
127
        /**
128
    		The database cache time 
129
         */
130
        protected $dbCacheTime = 0;
131
132
        /* --------------------------------------------------------------
133
         * GENERIC METHODS
134
         * ------------------------------------------------------------ */
135
136
        /**
137
         * Initialise the model, tie into the CodeIgniter superobject and
138
         * try our best to guess the table name.
139
         */
140
        public function __construct(Database $db = null) {
141
            $instance = null;
142
            if (is_object($db)) {
143
                $instance = $db;
144
            } else {
145
                $obj = & get_instance();
146
                if (isset($obj->database)){
147
                    /**
148
                     * NOTE: Need use "clone" because some Model need have the personal instance of the database library
149
                     * to prevent duplication
150
                     */
151
                    $instance = clone $obj->database;
152
                }
153
            }
154
            //Note: don't use the property direct access here as some update is done in the method
155
            //$this->setDatabaseInstance
156
            $this->setDatabaseInstance($instance);
157
158
            array_unshift($this->before_create, 'protect_attributes');
159
            array_unshift($this->before_update, 'protect_attributes');
160
            $this->_temporary_return_type = $this->return_type;
161
        }
162
163
        /* --------------------------------------------------------------
164
         * CRUD INTERFACE
165
         * ------------------------------------------------------------ */
166
167
        /**
168
         * Fetch a single record based on the primary key. Returns an object.
169
         */
170
        public function get($primary_value) {
171
            return $this->get_by($this->primary_key, $primary_value);
172
        }
173
174
175
        /**
176
         * Fetch a single record based on an arbitrary WHERE call. Can be
177
         * any valid value to DatabaseQueryBuilder->where().
178
         */
179
        public function get_by() {
180
            $where = func_get_args();
181
            $this->checkForSoftDelete();
182
            $this->_set_where($where);
183
            $this->trigger('before_get');
184
            $type = $this->getReturnType();
185
            $this->getQueryBuilder()->from($this->_table);
186
            $row = $this->_database->get($type);
187
            $this->_temporary_return_type = $this->return_type;
188
            $row = $this->trigger('after_get', $row);
189
            $this->_with = array();
190
            return $row;
191
        }
192
193
        /**
194
         * Fetch an array of records based on an array of primary values.
195
         */
196
        public function get_many($values) {
197
            $this->getQueryBuilder()->in($this->primary_key, $values);
198
            return $this->get_all();
199
        }
200
201
        /**
202
         * Fetch an array of records based on an arbitrary WHERE call.
203
         */
204
        public function get_many_by() {
205
            $where = func_get_args();
206
            $this->_set_where($where);
207
            return $this->get_all();
208
        }
209
210
        /**
211
         * Fetch all the records in the table. Can be used as a generic call
212
         * to $this->_database->get() with scoped methods.
213
         */
214
        public function get_all() {
215
            $this->trigger('before_get');
216
            $this->checkForSoftDelete();
217
            $type = $this->getReturnType();
218
            $this->getQueryBuilder()->from($this->_table);
219
            $result = $this->_database->getAll($type);
220
            $this->_temporary_return_type = $this->return_type;
221
            foreach ($result as $key => &$row) {
222
                $row = $this->trigger('after_get', $row, ($key == count($result) - 1));
223
            }
224
            $this->_with = array();
225
            return $result;
226
        }
227
228
        /**
229
         * Insert a new row into the table. $data should be an associative array
230
         * of data to be inserted. Returns newly created ID.
231
         * @see Database::insert
232
         */
233
        public function insert($data = array(), $skip_validation = FALSE, $escape = true) {
234
            if ($this->validateData($data, $skip_validation) !== FALSE) {
235
                $data = $this->trigger('before_create', $data);
236
                $this->getQueryBuilder()->from($this->_table);
237
                $this->_database->insert($data, $escape);
238
                $insert_id = $this->_database->insertId();
239
                $this->trigger('after_create', $insert_id);
240
                //if the table doesn't have the auto increment field or sequence, the value of 0 will be returned 
241
                $id = $insert_id;
242
                if (!$id) {
243
                    $id = true;
244
                }
245
                return $id;
246
            } 
247
            return FALSE;
248
        }
249
250
        /**
251
         * Insert multiple rows into the table. Returns an array of multiple IDs.
252
         */
253
        public function insert_many($data = array(), $skip_validation = FALSE, $escape = true) {
254
            $ids = array();
255
            foreach ($data as $key => $row) {
256
                $ids[] = $this->insert($row, $skip_validation, $escape);
257
            }
258
            return $ids;
259
        }
260
261
        /**
262
         * Updated a record based on the primary value.
263
         */
264
        public function update($primary_value, $data = array(), $skip_validation = FALSE, $escape = true) {
265
            $data = $this->trigger('before_update', $data);
266
            if ($this->validateData($data, $skip_validation) !== FALSE) {
267
                $this->getQueryBuilder()->where($this->primary_key, $primary_value)
268
                                        ->from($this->_table);
269
                $result = $this->_database->update($data, $escape);
270
                $this->trigger('after_update', array($data, $result));
271
                return $result;
272
            } 
273
            return FALSE;
274
        }
275
276
        /**
277
         * Update many records, based on an array of primary values.
278
         */
279
        public function update_many($primary_values, $data = array(), $skip_validation = FALSE, $escape = true) {
280
            $data = $this->trigger('before_update', $data);
281
            if ($this->validateData($data, $skip_validation) !== FALSE) {
282
                $this->getQueryBuilder()->in($this->primary_key, $primary_values)
283
                                        ->from($this->_table);
284
                $result = $this->_database->update($data, $escape);
285
                $this->trigger('after_update', array($data, $result));
286
                return $result;
287
            }
288
            return FALSE;
289
        }
290
291
        /**
292
         * Updated a record based on an arbitrary WHERE clause.
293
         */
294
        public function update_by() {
295
            $args = func_get_args();
296
            $data = array();
297
            if (count($args) == 2) {
298
                if (is_array($args[1])) {
299
                    $data = array_pop($args);
300
                }
301
            } else if (count($args) == 3) {
302
                if (is_array($args[2])) {
303
                    $data = array_pop($args);
304
                }
305
            }
306
            $data = $this->trigger('before_update', $data);
307
            if ($this->validate($data) !== FALSE) {
308
                $this->_set_where($args);
309
                $this->getQueryBuilder()->from($this->_table);
310
                $result = $this->_database->update($data);
311
                $this->trigger('after_update', array($data, $result));
312
                return $result;
313
            }
314
            return FALSE;
315
        }
316
317
        /**
318
         * Update all records
319
         */
320
        public function update_all($data = array(), $escape = true) {
321
            $data = $this->trigger('before_update', $data);
322
            $this->getQueryBuilder()->from($this->_table);
323
            $result = $this->_database->update($data, $escape);
324
            $this->trigger('after_update', array($data, $result));
325
            return $result;
326
        }
327
328
        /**
329
         * Delete a row from the table by the primary value
330
         */
331
        public function delete($id) {
332
            $this->trigger('before_delete', $id);
333
            $this->getQueryBuilder()->where($this->primary_key, $id);
334
            $result = false;
335
            $this->getQueryBuilder()->from($this->_table);  
336
            if ($this->soft_delete) {
337
                $result = $this->_database->update(array($this->soft_delete_key => TRUE));
338
            } else {
339
                $result = $this->_database->delete();
340
            }
341
            $this->trigger('after_delete', $result);
342
            return $result;
343
        }
344
345
        /**
346
         * Delete a row from the database table by an arbitrary WHERE clause
347
         */
348
        public function delete_by() {
349
            $where = func_get_args();
350
            $where = $this->trigger('before_delete', $where);
351
            $this->_set_where($where);
352
            $result = false;
353
            $this->getQueryBuilder()->from($this->_table);  
354
            if ($this->soft_delete) {
355
                $result = $this->_database->update(array($this->soft_delete_key => TRUE));
356
            } else {
357
                $result = $this->_database->delete();
358
            }
359
            $this->trigger('after_delete', $result);
360
            return $result;
361
        }
362
363
        /**
364
         * Delete many rows from the database table by multiple primary values
365
         */
366
        public function delete_many($primary_values) {
367
            $primary_values = $this->trigger('before_delete', $primary_values);
368
            $this->getQueryBuilder()->in($this->primary_key, $primary_values);
369
            $result = false;
370
            $this->getQueryBuilder()->from($this->_table);  
371
            if ($this->soft_delete) {
372
                $result = $this->_database->update(array($this->soft_delete_key => TRUE));
373
            } else {
374
                $result = $this->_database->delete();
375
            }
376
            $this->trigger('after_delete', $result);
377
            return $result;
378
        }
379
380
381
        /**
382
         * Truncates the table
383
         */
384
        public function truncate() {
385
            $this->getQueryBuilder()->from($this->_table); 
386
            $result = $this->_database->delete();
387
            return $result;
388
        }
389
390
        /* --------------------------------------------------------------
391
         * RELATIONSHIPS
392
         * ------------------------------------------------------------ */
393
394
        public function with($relationship) {
395
            $this->_with[] = $relationship;
396
            if (!in_array('relate', $this->after_get)) {
397
                $this->after_get[] = 'relate';
398
            }
399
            return $this;
400
        }
401
		
402
        /**
403
         * Relationship
404
         */
405
        public function relate($row) {
406
            if (empty($row)) {
407
                return $row;
408
            }
409
            $row = $this->relateBelongsTo($row);
410
            $row = $this->relateHasMany($row);
411
            return $row;
412
        }
413
414
        /* --------------------------------------------------------------
415
         * UTILITY METHODS
416
         * ------------------------------------------------------------ */
417
418
        /**
419
         * Retrieve and generate a form_dropdown friendly array
420
         */
421
        public function dropdown() {
422
            $args = func_get_args();
423
            if (count($args) == 2) {
424
                list($key, $value) = $args;
425
            } else {
426
                $key = $this->primary_key;
427
                $value = $args[0];
428
            }
429
            $this->trigger('before_dropdown', array($key, $value));
430
            $this->checkForSoftDelete();
431
            $this->getQueryBuilder()->select(array($key, $value))
432
                                    ->from($this->_table);
433
            $result = $this->_database->getAll();
434
            $options = array();
435
            foreach ($result as $row) {
436
                $options[$row->{$key}] = $row->{$value};
437
            }
438
            $options = $this->trigger('after_dropdown', $options);
439
            return $options;
440
        }
441
442
        /**
443
         * Fetch a count of rows based on an arbitrary WHERE call.
444
         */
445
        public function count_by() {
446
            $this->checkForSoftDelete();
447
            $where = func_get_args();
448
            $this->_set_where($where);
449
            $this->getQueryBuilder()->from($this->_table);
450
            $this->_database->getAll();
451
            return $this->_database->numRows();
452
        }
453
454
        /**
455
         * Fetch a total count of rows, disregarding any previous conditions
456
         */
457
        public function count_all() {
458
            $this->checkForSoftDelete();
459
            $this->getQueryBuilder()->from($this->_table);
460
            $this->_database->getAll();
461
            return $this->_database->numRows();
462
        }
463
		
464
        /**
465
         * Enabled cache temporary
466
         */
467
        public function cached($ttl = 0) {
468
            $this->_database = $this->_database->cached($ttl);
469
            return $this;
470
        }
471
472
        /**
473
         * Tell the class to skip the insert validation
474
         */
475
        public function skip_validation() {
476
            $this->skip_validation = TRUE;
477
            return $this;
478
        }
479
480
        /**
481
         * Get the skip validation status
482
         */
483
        public function get_skip_validation() {
484
            return $this->skip_validation;
485
        }
486
487
        /**
488
         * Return the next auto increment of the table. Only tested on MySQL.
489
         */
490
        public function get_next_id() {
491
            $this->getQueryBuilder()->select('AUTO_INCREMENT')
492
                                    ->from('information_schema.TABLES')
493
                                    ->where('TABLE_NAME', $this->_table)
494
                                    ->where('TABLE_SCHEMA', $this->_database->getConnection()->getDatabase());
495
            return (int) $this->_database->get()->AUTO_INCREMENT;
496
        }
497
498
        /**
499
         * Getter for the table name
500
         */
501
        public function table() {
502
            return $this->_table;
503
        }
504
505
        /* --------------------------------------------------------------
506
         * GLOBAL SCOPES
507
         * ------------------------------------------------------------ */
508
509
        /**
510
         * Return the next call as an array rather than an object
511
         */
512
        public function as_array() {
513
            $this->_temporary_return_type = 'array';
514
            return $this;
515
        }
516
517
        /**
518
         * Return the next call as an object rather than an array
519
         */
520
        public function as_object() {
521
            $this->_temporary_return_type = 'object';
522
            return $this;
523
        }
524
525
        /**
526
         * Don't care about soft deleted rows on the next call
527
         */
528
        public function with_deleted() {
529
            $this->_temporary_with_deleted = TRUE;
530
            return $this;
531
        }
532
533
        /**
534
         * Only get deleted rows on the next call
535
         */
536
        public function only_deleted() {
537
            $this->_temporary_only_deleted = TRUE;
538
            return $this;
539
        }
540
541
        /* --------------------------------------------------------------
542
         * OBSERVERS
543
         * ------------------------------------------------------------ */
544
545
        /**
546
         * MySQL DATETIME created_at and updated_at
547
         */
548
        public function created_at($row) {
549
            if (is_object($row)) {
550
                $row->created_at = date('Y-m-d H:i:s');
551
            } else {
552
                $row['created_at'] = date('Y-m-d H:i:s');
553
            }
554
            return $row;
555
        }
556
557
        public function updated_at($row) {
558
            if (is_object($row)) {
559
                $row->updated_at = date('Y-m-d H:i:s');
560
            } else {
561
                $row['updated_at'] = date('Y-m-d H:i:s');
562
            }
563
            return $row;
564
        }
565
566
        /**
567
         * Serialises data for you automatically, allowing you to pass
568
         * through objects and let it handle the serialisation in the background
569
         */
570
        public function serialize($row) {
571
            foreach ($this->callback_parameters as $column) {
572
                $row[$column] = serialize($row[$column]);
573
            }
574
            return $row;
575
        }
576
577
        public function unserialize($row) {
578
            foreach ($this->callback_parameters as $column) {
579
                if (is_array($row)) {
580
                    $row[$column] = unserialize($row[$column]);
581
                } else {
582
                    $row->$column = unserialize($row->$column);
583
                }
584
            }
585
            return $row;
586
        }
587
588
        /**
589
         * Protect attributes by removing them from $row array
590
         */
591
        public function protect_attributes($row) {
592
            foreach ($this->protected_attributes as $attr) {
593
                if (is_object($row) && isset($row->$attr)) {
594
                    unset($row->$attr);
595
                } else if (isset($row[$attr])) {
596
                    unset($row[$attr]);
597
                }
598
            }
599
            return $row;
600
        }
601
		
602
            /**
603
             * Return the database instance
604
             * @return Database the database instance
605
             */
606
        public function getDatabaseInstance() {
607
            return $this->_database;
608
        }
609
610
        /**
611
         * set the Database instance for future use
612
         * @param Database $db the database object
613
         */
614
        public function setDatabaseInstance($db) {
615
            $this->_database = $db;
616
            if ($this->dbCacheTime > 0) {
617
                $this->_database->setCache($this->dbCacheTime);
618
            }
619
            return $this;
620
        }
621
622
        /**
623
         * Return the queryBuilder instance this is the shortcut to database queryBuilder
624
         * @return object the DatabaseQueryBuilder instance
625
         */
626
        public function getQueryBuilder() {
627
            return $this->_database->getQueryBuilder();
628
        }
629
630
        /**
631
         * Set the DatabaseQueryBuilder instance for future use
632
         * @param object $queryBuilder the DatabaseQueryBuilder object
633
         * @return object
634
         */
635
        public function setQueryBuilder($queryBuilder) {
636
            $this->_database->setQueryBuilder($queryBuilder);
637
            return $this;
638
        }
639
640
        /* --------------------------------------------------------------
641
         * QUERY BUILDER DIRECT ACCESS METHODS
642
         * ------------------------------------------------------------ */
643
644
        /**
645
         * A wrapper to $this->getQueryBuilder()->orderBy()
646
         */
647
        public function order_by($criteria, $order = 'ASC') {
648
            if (is_array($criteria)) {
649
                foreach ($criteria as $key => $value) {
650
                    $this->getQueryBuilder()->orderBy($key, $value);
651
                }
652
            } else {
653
                $this->getQueryBuilder()->orderBy($criteria, $order);
654
            }
655
            return $this;
656
        }
657
658
        /**
659
         * A wrapper to $this->getQueryBuilder()->limit()
660
         */
661
        public function limit($offset = 0, $limit = 10) {
662
            $this->getQueryBuilder()->limit($offset, $limit);
663
            return $this;
664
        }
665
666
        /* --------------------------------------------------------------
667
         * INTERNAL METHODS
668
         * ------------------------------------------------------------ */
669
        
670
        /**
671
         * Validate the data using the validation rules
672
         * @param  mixed $data the data to validate before insert, update, etc.
673
         * @param boolean $skipValidation whether to skip validation or not
674
         * @return mixed
675
         */
676
        protected function validateData($data, $skipValidation) {
677
            if ($skipValidation === FALSE) {
678
                $data = $this->validate($data);
679
            }
680
            return $data;
681
        }
682
683
         /**
684
         * Get the return type array or object
685
         * @return string|boolean
686
         */
687
        protected function getReturnType(){
688
            $type = false;
689
            if ($this->_temporary_return_type == 'array') {
690
               $type = 'array';
691
            }
692
            return $type;
693
        }
694
695
         /**
696
         * Check if soft delete is enable setting the condition
697
         * @return object the current instance 
698
         */
699
        protected function checkForSoftDelete(){
700
            if ($this->soft_delete && $this->_temporary_with_deleted !== true) {
701
                $this->getQueryBuilder()->where($this->soft_delete_key, (bool) $this->_temporary_only_deleted);
702
            }
703
            return $this;
704
        }
705
706
         /**
707
         * Relate for "belongs_to" and "has_many"
708
         * @param  string $relationship the name of relation
709
         * @param  string|array $options      the model and primary key values
710
         * @param  object|array $row          the row to update
711
         * @param  string $type         the type can be "belongs_to", "has_many"
712
         * @return mixed               the final row values
713
         */
714
        protected function relateBelongsToAndHasMany($relationship, $options, $row, $type){
715
            if (in_array($relationship, $this->_with)) {
716
                get_instance()->loader->model($options['model'], $relationship . '_model');
717
718
                if($type == 'belongs_to'){
719
                    if (is_object($row)) {
720
                        $row->{$relationship} = $this->{$relationship . '_model'}->get($row->{$options['primary_key']});
721
                    } else {
722
                        $row[$relationship] = $this->{$relationship . '_model'}->get($row[$options['primary_key']]);
723
                    }
724
                } else {
725
                    if (is_object($row)) {
726
                        $row->{$relationship} = $this->{$relationship . '_model'}->get_many_by($options['primary_key'], $row->{$this->primary_key});
727
                    } else {
728
                        $row[$relationship] = $this->{$relationship . '_model'}->get_many_by($options['primary_key'], $row[$this->primary_key]);
729
                    }
730
                }
731
            }
732
            return $row;
733
        }
734
735
        /**
736
         * relate for the relation "belongs_to"
737
         * @return mixed
738
         */
739
        protected function relateBelongsTo($row) {
740
            foreach ($this->belongs_to as $key => $value) {
741
                if (is_string($value)) {
742
                    $relationship = $value;
743
                    $options = array('primary_key' => $value . '_id', 'model' => $value . '_model');
744
                } else {
745
                    $relationship = $key;
746
                    $options = $value;
747
                }
748
                $row = $this->relateBelongsToAndHasMany($relationship, $options, $row, 'belongs_to');
749
            }
750
            return $row;
751
        }
752
753
        /**
754
         * relate for the relation "has_many"
755
         * @return mixed
756
         */
757
        protected function relateHasMany($row) {
758
            foreach ($this->has_many as $key => $value) {
759
                if (is_string($value)) {
760
                    $relationship = $value;
761
                    $options = array('primary_key' => $this->_table . '_id', 'model' => $value . '_model');
762
                } else {
763
                    $relationship = $key;
764
                    $options = $value;
765
                }
766
                $row = $this->relateBelongsToAndHasMany($relationship, $options, $row, 'belongs_to');
767
            }
768
            return $row;
769
        }
770
		
771
        /**
772
         * Trigger an event and call its observers. Pass through the event name
773
         * (which looks for an instance variable $this->event_name), an array of
774
         * parameters to pass through and an optional 'last in interation' boolean
775
         */
776
        protected function trigger($event, $data = FALSE, $last = TRUE) {
777
            if (isset($this->$event) && is_array($this->$event)) {
778
                foreach ($this->$event as $method) {
779
                    if (strpos($method, '(')) {
780
                        preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches);
781
                        $method = $matches[1];
782
                        $this->callback_parameters = explode(',', $matches[3]);
783
                    }
784
                    $data = call_user_func_array(array($this, $method), array($data, $last));
785
                }
786
            }
787
            return $data;
788
        }
789
790
        /**
791
         * Run validation on the passed data
792
         */
793
        protected function validate(array $data) {
794
            if ($this->skip_validation || empty($this->validate)) {
795
                return $data;
796
            }
797
            get_instance()->formvalidation->setData($data);
798
            get_instance()->formvalidation->setRules($this->validate);
799
800
            if (get_instance()->formvalidation->validate()) {
801
                return $data;
802
            }
803
            return FALSE;
804
        }
805
		
806
		
807
        /**
808
         * Set WHERE parameters, when is array
809
         * @param array $params
810
         */
811
        protected function _set_where_array(array $params) {
812
            foreach ($params as $field => $filter) {
813
                if (is_array($filter)) {
814
                    $this->getQueryBuilder()->in($field, $filter);
815
                } else {
816
                    if (is_int($field)) {
817
                        $this->getQueryBuilder()->where($filter);
818
                    } else {
819
                        $this->getQueryBuilder()->where($field, $filter);
820
                    }
821
                }
822
            }
823
        }
824
825
826
        /**
827
         * Set WHERE parameters, cleverly
828
         */
829
        protected function _set_where($params) {
830
            if (count($params) == 1 && is_array($params[0])) {
831
                $this->_set_where_array($params[0]);
832
            } else if (count($params) == 1) {
833
                $this->getQueryBuilder()->where($params[0]);
834
            } else if (count($params) == 2) {
835
                if (is_array($params[1])) {
836
                    $this->getQueryBuilder()->in($params[0], $params[1]);
837
                } else {
838
                    $this->getQueryBuilder()->where($params[0], $params[1]);
839
                }
840
            } else if (count($params) == 3) {
841
                $this->getQueryBuilder()->where($params[0], $params[1], $params[2]);
842
            } else {
843
                if (is_array($params[1])) {
844
                    $this->getQueryBuilder()->in($params[0], $params[1]);
845
                } else {
846
                    $this->getQueryBuilder()->where($params[0], $params[1]);
847
                }
848
            }
849
        }
850
851
        /**
852
            Shortcut to controller
853
         */
854
        public function __get($key) {
855
            return get_instance()->{$key};
856
        }
857
858
    }
859