GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (423)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

myth/Models/CIDbModel.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace Myth\Models;
2
/**
3
 * Sprint
4
 *
5
 * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 *
25
 * @package     Sprint
26
 * @author      Lonnie Ezell
27
 * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
 * @license     http://opensource.org/licenses/MIT  (MIT)
29
 * @link        http://sprintphp.com
30
 * @since       Version 1.0
31
 */
32
33
//--------------------------------------------------------------------
34
35
/**
36
 * BF_Model
37
 *
38
 * An extension of CodeIgniter's built-in model that provides a convenient
39
 * base to quickly and easily build your database-backed models off of.
40
 *
41
 * Provides observers, soft-deletes, basic CRUD functions, helpful functions,
42
 * and more.
43
 *
44
 * This pulls many ideas and inspiration from Jamie Rumbelow's excellent MY_Model
45
 * and the ideas described in his CodeIgniter Handbook, as well as from Laravel
46
 * and Rails.
47
 *
48
 * NOTE: The methods in this model do not take advantage of the clean syntax of
49
 * method chaining. THIS IS BY DESIGN! and allows our mocking of the database
50
 * class to work in a simple and clean way. Do not change this.
51
 *
52
 * @package Bonfire
53
 * @author Bonfire Dev Team
54
 * @license http://opensource.org/licenses/MIT
55
 *
56
 * /**
57
 * The following properties are used to provide autocomplete for IDE's.
58
 *
59
 * Thanks to:  https://gist.github.com/topdown/1697338
60
 *
61
 * @property \CI_DB_query_builder    $db
62
 * @property \CI_DB_utility          $dbutil
63
 * @property \CI_DB_forge            $dbforge
64
 * @property \CI_Benchmark           $benchmark
65
 * @property \CI_Calendar            $calendar
66
 * @property \CI_Cart                $cart
67
 * @property \CI_Config              $config
68
 * @property \CI_Controller          $controller
69
 * @property \CI_Email               $email
70
 * @property \CI_Encrypt             $encrypt
71
 * @property \CI_Exceptions          $exceptions
72
 * @property \CI_Form_validation     $form_validation
73
 * @property \CI_Ftp                 $ftp
74
 * @property \CI_Hooks               $hooks
75
 * @property \CI_Image_lib           $image_lib
76
 * @property \CI_Input               $input
77
 * @property \CI_Lang                $lang
78
 * @property \CI_Loader              $load
79
 * @property \CI_Log                 $log
80
 * @property \CI_Model               $model
81
 * @property \CI_Output              $output
82
 * @property \CI_Pagination          $pagination
83
 * @property \CI_Parser              $parser
84
 * @property \CI_Profiler            $profiler
85
 * @property \CI_Router              $router
86
 * @property \CI_Session             $session
87
 * @property \CI_Table               $table
88
 * @property \CI_Trackback           $trackback
89
 * @property \CI_Typography          $typography
90
 * @property \CI_Unit_test           $unit_test
91
 * @property \CI_Upload              $upload
92
 * @property \CI_URI                 $uri
93
 * @property \CI_User_agent          $user_agent
94
 * @property \CI_Xmlrpc              $xmlrpc
95
 * @property \CI_Xmlrpcs             $xmlrpcs
96
 * @property \CI_Zip                 $zip
97
 * @property \CI_Javascript          $javascript
98
 * @property \CI_Jquery              $jquery
99
 * @property \CI_Utf8                $utf8
100
 * @property \CI_Security            $security
101
 */
102
class CIDbModel
103
{
104
105
    /**
106
     * The model's default table name.
107
     *
108
     * @var string;
109
     */
110
    protected $table_name;
111
112
    /**
113
     * The model's default primary key.
114
     *
115
     * @var string
116
     */
117
    protected $primary_key = 'id';
118
119
    /**
120
     * The type of date/time field used for created_on and modified_on fields.
121
     * Valid types are: 'int', 'datetime', 'date'
122
     *
123
     * @var string
124
     * @access protected
125
     */
126
    protected $date_format = 'datetime';
127
128
    /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
129
        Var: $log_user
130
        If TRUE, will log user id for 'created_by', 'modified_by' and 'deleted_by'.
131
132
        Access:
133
            Protected
134
    */
135
    protected $log_user = FALSE;
136
137
138
139
    /**
140
     * Whether or not to auto-fill a 'created_on' field on inserts.
141
     *
142
     * @var boolean
143
     * @access protected
144
     */
145
    protected $set_created = TRUE;
146
147
    /**
148
     * Field name to use to the created time column in the DB table.
149
     *
150
     * @var string
151
     * @access protected
152
     */
153
    protected $created_field = 'created_on';
154
155
    /*
156
        Var: $created_by_field
157
        Field name to use to the created by column in the DB table.
158
159
        Access:
160
            Protected
161
    */
162
    protected $created_by_field = 'created_by';
163
164
165
166
    /**
167
     * Whether or not to auto-fill a 'modified_on' field on updates.
168
     *
169
     * @var boolean
170
     * @access protected
171
     */
172
    protected $set_modified = TRUE;
173
174
    /**
175
     * Field name to use to the modified time column in the DB table.
176
     *
177
     * @var string
178
     * @access protected
179
     */
180
    protected $modified_field = 'modified_on';
181
182
    /*
183
        Var: $modified_by_field
184
        Field name to use to the modified by column in the DB table.
185
186
        Access:
187
            Protected
188
    */
189
    protected $modified_by_field = 'modified_by';
190
191
192
    /**
193
     * Support for soft_deletes.
194
     */
195
    protected $soft_deletes = FALSE;
196
    protected $soft_delete_key = 'deleted';
197
    protected $temp_with_deleted = FALSE;
198
199
    /*
200
        Var: $deleted_by_field
201
        Field name to use for the deleted by column in the DB table.
202
203
        Access:
204
            Protected
205
    */
206
    protected $deleted_by_field = 'deleted_by';
207
208
209
210
    /**
211
     * Various callbacks available to the class. They are simple lists of
212
     * method names (methods will be ran on $this).
213
     */
214
    protected $before_insert = array();
215
    protected $after_insert = array();
216
    protected $before_update = array();
217
    protected $after_update = array();
218
    protected $before_find = array();
219
    protected $after_find = array();
220
    protected $before_delete = array();
221
    protected $after_delete = array();
222
223
    protected $callback_parameters = array();
224
225
226
227
    /*
228
        If TRUE, inserts will return the last_insert_id. However,
229
        this can potentially slow down large imports drastically
230
        so you can turn it off with the return_insert_id(false) method.
231
     */
232
    protected $return_insert_id = true;
233
234
    /**
235
     * By default, we return items as objects. You can change this for the
236
     * entire class by setting this value to 'array' instead of 'object'.
237
     * Alternatively, you can do it on a per-instance basis using the
238
     * 'as_array()' and 'as_object()' methods.
239
     */
240
    protected $return_type = 'object';
241
    protected $temp_return_type = NULL;
242
243
    /**
244
     * Protected, non-modifiable attributes
245
     */
246
    protected $protected_attributes = array();
247
248
249
250
    /**
251
     * An array of validation rules. This needs to be the same format
252
     * as validation rules passed to the Form_validation library.
253
     */
254
    protected $validation_rules = array();
255
256
    /**
257
     * Optionally skip the validation. Used in conjunction with
258
     * skip_validation() to skip data validation for any future calls.
259
     */
260
    protected $skip_validation = FALSE;
261
262
    /**
263
     * An array of extra rules to add to validation rules during inserts only.
264
     * Often used for adding 'required' rules to fields on insert, but not udpates.
265
     *
266
     *   array( 'username' => 'required|strip_tags' );
267
     * @var array
268
     */
269
    protected $insert_validate_rules = array();
270
271
272
273
    /**
274
     * @var Array Columns for the model's database fields
275
     *
276
     * This can be set to avoid a database call if using $this->prep_data()
277
     */
278
    protected $fields = array();
279
280
    //--------------------------------------------------------------------
281
282
    /**
283
     * Does basic setup. Can pass the database connection into the constructor
284
     * to use that $db instead of the global CI one.
285
     *
286
     * @param object $db // A database/driver instance
287
     * @param object $form_validation // A form_validation library instance
288
     */
289
    public function __construct($db = null, $form_validation = null)
290
    {
291
        // Always protect our attributes
292
        array_unshift($this->before_insert, 'protect_attributes');
293
        array_unshift($this->before_update, 'protect_attributes');
294
295
        // Check our auto-set features and make sure they are part of
296
        // our observer system.
297
        if ($this->set_created === true) array_unshift($this->before_insert, 'created_on');
298
        if ($this->set_modified === true) array_unshift($this->before_update, 'modified_on');
299
300
        // Make sure our temp return type is correct.
301
        $this->temp_return_type = $this->return_type;
302
303
        // Make sure our database is loaded
304
        if (!is_null($db)) {
305
            $this->db = $db;
306
        }
307
        else {
308
            // Auto Init the damn database....
309
            $this->load->database();
310
        }
311
312
        // Do we have a form_validation library?
313
        if (! is_null($form_validation)) {
314
            $this->form_validation = $form_validation;
315
        }
316
        else {
317
            $this->load->library('form_validation');
318
        }
319
        
320
        log_message('debug', 'CIDbModel Class Initialized');
321
    }
322
323
    //--------------------------------------------------------------------
324
325
    //--------------------------------------------------------------------
326
    // CRUD Methods
327
    //--------------------------------------------------------------------
328
329
    /**
330
     * A simple way to grab the first result of a search only.
331
     */
332
    public function first()
333
    {
334
        $rows = $this->limit(1, 0)->find_all();
335
336
        if (is_array($rows) && count($rows)) {
337
            return $rows[0];
338
        }
339
340
        return $rows;
341
    }
342
343
    //--------------------------------------------------------------------
344
345
346
    /**
347
     * Finds a single record based on it's primary key. Will ignore deleted rows.
348
     *
349
     * @param  mixed $id The primary_key value of the object to retrieve.
350
     * @return object
351
     */
352
    public function find($id)
353
    {
354
        $this->trigger('before_find', ['id' => $id, 'method' => 'find']);
355
356
        // Ignore any soft-deleted rows
357 View Code Duplication
        if ($this->soft_deletes) {
358
            // We only need to modify the where statement if
359
            // temp_with_deleted is false.
360
            if ($this->temp_with_deleted !== true) {
361
                $this->db->where($this->soft_delete_key, false);
362
            }
363
364
            $this->temp_with_deleted = false;
365
        }
366
367
        $this->db->where($this->primary_key, $id);
368
        $row = $this->db->get($this->table_name);
369
        $row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
370
371 View Code Duplication
        if ( ! empty($row))
372
        {
373
            $row = $this->trigger('after_find', ['id' => $id, 'method' => 'find', 'fields' => $row]);
374
        }
375
376
        // Reset our return type
377
        $this->temp_return_type = $this->return_type;
378
379
        return $row;
380
    }
381
382
    //--------------------------------------------------------------------
383
384
    /**
385
     * Fetch a single record based on an arbitrary WHERE call. Can be
386
     * any valid value to $this->db->where(). Will not pull in deleted rows
387
     * if using soft deletes.
388
     *
389
     * @return object
390
     */
391
    public function find_by()
392
    {
393
        $where = func_get_args();
394
        $this->_set_where($where);
395
396
        // Ignore any soft-deleted rows
397 View Code Duplication
        if ($this->soft_deletes) {
398
            // We only need to modify the where statement if
399
            // temp_with_deleted is false.
400
            if ($this->temp_with_deleted !== true) {
401
                $this->db->where($this->soft_delete_key, false);
402
            }
403
404
            $this->temp_with_deleted = false;
405
        }
406
407
        $this->trigger('before_find', ['method' => 'find_by', 'fields' => $where]);
408
409
        $row = $this->db->get($this->table_name);
410
        $row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
411
412 View Code Duplication
        if ( ! empty($row))
413
        {
414
            $row = $this->trigger('after_find', ['method' => 'find_by', 'fields' => $row]);
415
        }
416
417
        // Reset our return type
418
        $this->temp_return_type = $this->return_type;
419
420
        return $row;
421
    }
422
423
    //--------------------------------------------------------------------
424
425
    /**
426
     * Retrieves a number of items based on an array of primary_values passed in.
427
     *
428
     * @param  array $values An array of primary key values to find.
429
     *
430
     * @return object or FALSE
431
     */
432
    public function find_many($values)
433
    {
434
        $this->db->where_in($this->primary_key, $values);
435
436
        return $this->find_all();
437
    }
438
439
    //--------------------------------------------------------------------
440
441
    /**
442
     * Retrieves a number of items based on an arbitrary WHERE call. Can be
443
     * any set of parameters valid to $db->where.
444
     *
445
     * @return object or FALSE
446
     */
447
    public function find_many_by()
448
    {
449
        $where = func_get_args();
450
        $this->_set_where($where);
451
452
        return $this->find_all();
453
    }
454
455
    //--------------------------------------------------------------------
456
457
    /**
458
     * Fetch all of the records in the table. Can be used with scoped calls
459
     * to restrict the results.
460
     *
461
     * @return object or FALSE
462
     */
463
    public function find_all()
464
    {
465
        $this->trigger('before_find', ['method' => 'find_all']);
466
467
        // Ignore any soft-deleted rows
468 View Code Duplication
        if ($this->soft_deletes) {
469
            // We only need to modify the where statement if
470
            // temp_with_deleted is false.
471
            if ($this->temp_with_deleted !== true) {
472
                $this->db->where($this->soft_delete_key, false);
473
            }
474
475
            $this->temp_with_deleted = false;
476
        }
477
478
        $rows = $this->db->get($this->table_name);
479
        $rows = $this->temp_return_type == 'array' ? $rows->result_array() : $rows->result($this->temp_return_type);
480
481
        if (is_array($rows)) {
482
            foreach ($rows as $key => &$row) {
483
                $row = $this->trigger('after_find', ['method' => 'find_all', 'fields' => $row] );
484
            }
485
        }
486
487
        // Reset our return type
488
        $this->temp_return_type = $this->return_type;
489
490
        return $rows;
491
    }
492
493
    //--------------------------------------------------------------------
494
495
    /**
496
     * Inserts data into the database.
497
     *
498
     * @param  array $data An array of key/value pairs to insert to database.
499
     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
500
     * @return mixed       The primary_key value of the inserted record, or FALSE.
501
     */
502 View Code Duplication
    public function insert($data, $skip_validation = null)
503
    {
504
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
505
506
        if ($skip_validation === FALSE) {
507
            $data = $this->validate($data, 'insert', $skip_validation);
508
        }
509
510
        if ($data !== FALSE) {
511
            $data = $this->trigger('before_insert', ['method' => 'insert', 'fields' => $data]);
512
513
            $this->db->insert($this->table_name, $this->prep_data($data) );
514
515
            if ($this->return_insert_id) {
516
                $id = $this->db->insert_id();
517
518
                $this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method' => 'insert']);
519
520
                return $id;
521
            }
522
523
            return TRUE;
524
        } else {
525
            return FALSE;
526
        }
527
    }
528
529
    //--------------------------------------------------------------------
530
531
    /**
532
     * Inserts multiple rows into the database at once. Takes an associative
533
     * array of value pairs.
534
     *
535
     * $data = array(
536
     *     array(
537
     *         'title' => 'My title'
538
     *     ),
539
     *     array(
540
     *         'title'  => 'My Other Title'
541
     *     )
542
     * );
543
     *
544
     * @param  array $data An associate array of rows to insert
545
     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
546
     * @return bool
547
     */
548
    public function insert_batch($data, $skip_validation = null)
549
    {
550
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
551
552
        if ($skip_validation === FALSE) {
553
            $data = $this->validate($data, 'insert', $skip_validation);
554
        }
555
556
        if ($data !== FALSE) {
557
            $data['batch'] = true;
558
            $data = $this->trigger('before_insert', ['method' => 'insert_batch', 'fields' => $data] );
559
            unset($data['batch']);
560
561
            return $this->db->insert_batch($this->table_name, $data);
562
        } else {
563
            return FALSE;
564
        }
565
    }
566
567
    //--------------------------------------------------------------------
568
569
    /**
570
     * Performs the SQL standard for a combined DELETE + INSERT, using
571
     * PRIMARY and UNIQUE keys to determine which row to replace.
572
     *
573
     * See CI's documentation for the replace method. We simply wrap
574
     * our validation and triggers around their method.
575
     *
576
     * @param $data
577
     * @param null $skip_validation
578
     * @return bool
579
     */
580
    public function replace($data, $skip_validation=null)
581
    {
582
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
583
584
        if ($skip_validation === FALSE) {
585
            $data = $this->validate($data, 'insert', $skip_validation);
586
        }
587
588
        if ($data !== FALSE) {
589
            $this->db->replace($this->table_name, $this->prep_data($data));
590
591
            if ($this->return_insert_id) {
592
                $id = $this->db->insert_id();
593
594
                $this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method'=>'replace']);
595
596
                return $id;
597
            }
598
599
            return TRUE;
600
        } else {
601
            return FALSE;
602
        }
603
    }
604
605
    //--------------------------------------------------------------------
606
607
608
    /**
609
     * Updates an existing record in the database.
610
     *
611
     * @param  mixed $id The primary_key value of the record to update.
612
     * @param  array $data An array of value pairs to update in the record.
613
     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
614
     * @return bool
615
     */
616
    public function update($id, $data, $skip_validation = null)
617
    {
618
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
619
620
        if ($skip_validation === FALSE) {
621
            $data = $this->validate($data);
622
        }
623
624
        // Will be false if it didn't validate.
625
        if ($data !== FALSE) {
626
            
627
            $data = $this->trigger('before_update', ['id' => $id, 'method' =>'update', 'fields' => $data] );
628
            
629
            $this->db->where($this->primary_key, $id);
630
            $this->db->set( $this->prep_data($data) );
631
            $result = $this->db->update($this->table_name);
632
633
            $this->trigger('after_update', ['id' => $id, 'fields' => $data, 'result' => $result, 'method' => 'update']);
634
635
            return $result;
636
        } else {
637
            return FALSE;
638
        }
639
    }
640
641
    //--------------------------------------------------------------------
642
643
    /**
644
     * Updates multiple records in the database at once.
645
     *
646
     * $data = array(
647
     *     array(
648
     *         'title'  => 'My title',
649
     *         'body'   => 'body 1'
650
     *     ),
651
     *     array(
652
     *         'title'  => 'Another Title',
653
     *         'body'   => 'body 2'
654
     *     )
655
     * );
656
     *
657
     * The $where_key should be the name of the column to match the record on.
658
     * If $where_key == 'title', then each record would be matched on that
659
     * 'title' value of the array. This does mean that the array key needs
660
     * to be provided with each row's data.
661
     *
662
     * @param  array $data An associate array of row data to update.
663
     * @param  string $where_key The column name to match on.
664
     * @return bool
665
     */
666
    public function update_batch($data, $where_key)
667
    {
668
        foreach ($data as &$row) {
669
            $row = $this->trigger('before_update', ['method' => 'update_batch', 'fields' => $row] );
670
        }
671
672
        $result = $this->db->update_batch($this->table_name, $data, $where_key);
673
674
        foreach ($data as &$row) {
675
            $this->trigger('after_update', ['fields' => $data, 'result' => $result, 'method' => 'update_batch']);
676
        }
677
678
        return $result;
679
    }
680
681
    //--------------------------------------------------------------------
682
683
    /**
684
     * Updates many records by an array of ids.
685
     *
686
     * While update_batch() allows modifying multiple, arbitrary rows of data
687
     * on each row, update_many() sets the same values for each row.
688
     *
689
     * $ids = array(1, 2, 3, 5, 12);
690
     * $data = array(
691
     *     'deleted_by' => 1
692
     * );
693
     *
694
     * $this->model->update_many($ids, $data);
695
     *
696
     * @param  array $ids An array of primary_key values to update.
697
     * @param  array $data An array of value pairs to modify in each row.
698
     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
699
     * @return bool
700
     */
701
    public function update_many($ids, $data, $skip_validation = null)
702
    {
703
        if (!is_array($ids) || count($ids) == 0) return NULL;
704
705
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
706
707
        if ($skip_validation === FALSE) {
708
            $data = $this->validate($data, 'update', $skip_validation);
709
        }
710
711
        $data = $this->trigger('before_update', ['ids' => $ids, 'method' => 'update_many', 'fields' => $data]);
712
713
        // Will be false if it didn't validate.
714
        if ($data !== FALSE) {
715
            $this->db->where_in($this->primary_key, $ids);
716
            $this->db->set($data);
717
            $result = $this->db->update($this->table_name);
718
719
            $this->trigger('after_update', ['ids' => $ids, 'fields' => $data, 'result'=>$result, 'method' => 'update_many']);
720
721
            return $result;
722
        } else {
723
            return FALSE;
724
        }
725
    }
726
727
    //--------------------------------------------------------------------
728
729
    /**
730
     * Update records in the database using a standard WHERE clause.
731
     *
732
     * Your last parameter should be the $data array with values to update
733
     * on the rows. Any additional parameters should be provided to make up
734
     * a typical WHERE clause. This could be a single array, or a column name
735
     * and a value.
736
     *
737
     * $data = array('deleted_by' => 1);
738
     * $wheres = array('user_id' => 15);
739
     *
740
     * $this->update_by($wheres, $data);
741
     * $this->update_by('user_id', 15, $data);
742
     *
743
     * @param array $data An array of data pairs to update
744
     * @param one or more WHERE-acceptable entries.
745
     * @return bool
746
     */
747
    public function update_by()
748
    {
749
        $args = func_get_args();
750
        $data = array_pop($args);
751
        $this->_set_where($args);
752
753
        $data = $this->trigger('before_update', ['method' => 'update_by', 'fields' => $data]);
754
755
        // Will be false if it didn't validate.
756
        if ($this->validate($data) !== FALSE) {
757
            $this->db->set( $this->prep_data($data) );
758
            $result = $this->db->update($this->table_name);
759
760
            $this->trigger('after_update', ['method' => 'update_by', 'fields' => $data, 'result' => $result] );
761
762
            return $result;
763
        } else {
764
            return FALSE;
765
        }
766
    }
767
768
    //--------------------------------------------------------------------
769
770
    /**
771
     * Updates all records and sets the value pairs passed in the array.
772
     *
773
     * @param  array $data An array of value pairs with the data to change.
774
     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
775
     * @return bool
776
     */
777 View Code Duplication
    public function update_all($data, $skip_validation = FALSE)
778
    {
779
        $data = $this->trigger('before_update', ['method' => 'update_all', 'fields' => $data] );
780
781
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
782
783
        if ($skip_validation === FALSE) {
784
            $data = $this->validate($data);
785
        }
786
787
        // Will be false if it didn't validate.
788
        if ($data !== FALSE) {
789
            $this->db->set( $this->prep_data($data) );
790
            $result = $this->db->update($this->table_name);
791
792
            $this->trigger('after_update', ['method' => 'update_all', 'fields' => $data, 'result' => $result] );
793
794
            return $result;
795
        } else {
796
            return FALSE;
797
        }
798
    }
799
800
    //--------------------------------------------------------------------
801
802
    /**
803
     * Increments the value of field for a given row, selected by the
804
     * primary key for the table.
805
     *
806
     * @param $id
807
     * @param $field
808
     * @param int $value
809
     * @return mixed
810
     */
811 View Code Duplication
    public function increment($id, $field, $value=1)
812
    {
813
        $value = (int)abs($value);
814
815
        $this->db->where($this->primary_key, $id);
816
        $this->db->set($field, "{$field}+{$value}", false);
817
818
        return $this->db->update($this->table_name);
819
    }
820
821
    //--------------------------------------------------------------------
822
823
    /**
824
     * Increments the value of field for a given row, selected by the
825
     * primary key for the table.
826
     *
827
     * @param $id
828
     * @param $field
829
     * @param int $value
830
     * @return mixed
831
     */
832 View Code Duplication
    public function decrement($id, $field, $value=1)
833
    {
834
        $value = (int)abs($value);
835
836
        $this->db->where($this->primary_key, $id);
837
        $this->db->set($field, "{$field}-{$value}", false);
838
839
        return $this->db->update($this->table_name);
840
    }
841
842
    //--------------------------------------------------------------------
843
844
    /**
845
     * Deletes a row by it's primary key value.
846
     *
847
     * @param  mixed $id The primary key value of the row to delete.
848
     * @return bool
849
     */
850
    public function delete($id)
851
    {
852
        $this->trigger('before_delete', ['id' => $id, 'method' => 'delete'] );
853
854
        $this->db->where($this->primary_key, $id);
855
856 View Code Duplication
        if ($this->soft_deletes) {
857
            $sets = $this->log_user && is_object($this->authenticate)
858
                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
859
                : array($this->soft_delete_key => 1);
860
861
            $result = $this->db->update($this->table_name, $sets);
862
        } // Hard Delete
863
        else {
864
            $result = $this->db->delete($this->table_name);
865
        }
866
867
        $this->trigger('after_delete', ['id' => $id, 'method' => 'delete', 'result' => $result] );
868
869
        return $result;
870
    }
871
872
    //--------------------------------------------------------------------
873
874
    public function delete_by()
875
    {
876
        $where = func_get_args();
877
        $this->_set_where($where);
878
879
        $where = $this->trigger('before_delete', ['method' => 'delete_by', 'fields' => $where]);
880
881 View Code Duplication
        if ($this->soft_deletes) {
882
            $sets = $this->log_user && is_object($this->authenticate)
883
                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
884
                : array($this->soft_delete_key => 1);
885
886
            $result = $this->db->update($this->table_name, $sets);
887
        } else {
888
            $result = $this->db->delete($this->table_name);
889
        }
890
891
        $this->trigger('after_delete', ['method' => 'delete_by', 'fields' => $where, 'result' => $result] );
892
893
        return $result;
894
    }
895
896
    //--------------------------------------------------------------------
897
898
    public function delete_many($ids)
899
    {
900
        if (!is_array($ids) || count($ids) == 0) return NULL;
901
902
        $ids = $this->trigger('before_delete', ['ids' => $ids, 'method' => 'delete_many'] );
903
904
        $this->db->where_in($this->primary_key, $ids);
905
906 View Code Duplication
        if ($this->soft_deletes) {
907
            $sets = $this->log_user && is_object($this->authenticate)
908
                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
909
                : array($this->soft_delete_key => 1);
910
911
            $result = $this->db->update($this->table_name, $sets);
912
        } else {
913
            $result = $this->db->delete($this->table_name);
914
        }
915
916
        $this->trigger('after_delete', ['ids' => $ids, 'method' => 'delete_many', 'result' => $result]);
917
918
        return $result;
919
    }
920
921
    //--------------------------------------------------------------------
922
923
    //--------------------------------------------------------------------
924
    // Scope Methods
925
    //--------------------------------------------------------------------
926
927
    /**
928
     * Sets the value of the soft deletes flag.
929
     *
930
     * @param  boolean $val If TRUE, should perform a soft delete. If FALSE, a hard delete.
931
     */
932
    public function soft_delete($val = TRUE)
933
    {
934
        $this->soft_deletes = $val;
935
936
        return $this;
937
    }
938
939
    //--------------------------------------------------------------------
940
941
    /**
942
     * Temporarily sets our return type to an array.
943
     */
944
    public function as_array()
945
    {
946
        $this->temp_return_type = 'array';
947
948
        return $this;
949
    }
950
951
    //--------------------------------------------------------------------
952
953
    /**
954
     * Temporarily sets our return type to an object.
955
     *
956
     * If $class is provided, the rows will be returned as objects that
957
     * are instances of that class. $class MUST be an fully qualified
958
     * class name, meaning that it must include the namespace, if applicable.
959
     *
960
     * @param string $class
961
     * @return $this
962
     */
963
    public function as_object($class=null)
964
    {
965
        $this->temp_return_type = ! empty($class) ? $class : 'object';
966
967
        return $this;
968
    }
969
970
    //--------------------------------------------------------------------
971
972
    /**
973
     * Also fetches deleted items for this request only.
974
     */
975
    public function with_deleted()
976
    {
977
        $this->temp_with_deleted = TRUE;
978
979
        return $this;
980
    }
981
982
    //--------------------------------------------------------------------
983
984
    /**
985
     * Returns whether the current setup will return
986
     * soft deleted rows.
987
     *
988
     * @return bool
989
     */
990
    public function get_with_deleted()
991
    {
992
        return $this->temp_with_deleted;
993
    }
994
995
    //--------------------------------------------------------------------
996
997
998
    /**
999
     * Sets the $skip_validation parameter.
1000
     *
1001
     * @param bool $skip
1002
     * @return $this
1003
     */
1004
    public function skip_validation($skip = true)
1005
    {
1006
        $this->skip_validation = $skip;
1007
1008
        return $this;
1009
    }
1010
1011
    //--------------------------------------------------------------------
1012
1013
1014
    //--------------------------------------------------------------------
1015
    // Utility Methods
1016
    //--------------------------------------------------------------------
1017
1018
    /**
1019
     * Counts number of rows modified by an arbitrary WHERE call.
1020
     * @return INT
1021
     */
1022
    public function count_by()
1023
    {
1024
        $where = func_get_args();
1025
        $this->_set_where($where);
1026
1027
        return $this->db->count_all_results($this->table_name);
1028
    }
1029
1030
    //--------------------------------------------------------------------
1031
1032
    /**
1033
     * Counts total number of records, disregarding any previous conditions.
1034
     *
1035
     * @return int
1036
     */
1037
    public function count_all()
1038
    {
1039
        return $this->db->count_all($this->table_name);
1040
    }
1041
1042
    //--------------------------------------------------------------------
1043
1044
    /**
1045
     * Getter for the table name.
1046
     *
1047
     * @return string The name of the table used by this class.
1048
     */
1049
    public function table()
1050
    {
1051
        return $this->table_name;
1052
    }
1053
1054
    //--------------------------------------------------------------------
1055
1056
    /**
1057
     * Set the return_insert_id value.
1058
     *
1059
     * @param  boolean $return If TRUE, insert will return the insert_id.
1060
     */
1061
    public function return_insert_id($return = true)
1062
    {
1063
        $this->return_insert_id = (bool)$return;
1064
1065
        return $this;
1066
    }
1067
1068
    //--------------------------------------------------------------------
1069
1070
    /**
1071
     * A convenience method to return only a single field of the specified row.
1072
     *
1073
     * @param mixed $id The primary_key value to match against.
1074
     * @param string $field The field to search for.
1075
     *
1076
     * @return bool|mixed The value of the field.
1077
     */
1078
    public function get_field($id = NULL, $field = '')
1079
    {
1080
        $this->db->select($field);
1081
        $this->db->where($this->primary_key, $id);
1082
        $query = $this->db->get($this->table_name);
1083
1084
        if ($query && $query->num_rows() > 0) {
1085
            return $query->row()->$field;
1086
        }
1087
1088
        return FALSE;
1089
1090
    }
1091
1092
    //---------------------------------------------------------------
1093
1094
    /**
1095
     * Checks whether a field/value pair exists within the table.
1096
     *
1097
     * @param string $field The field to search for.
1098
     * @param string $value The value to match $field against.
1099
     *
1100
     * @return bool TRUE/FALSE
1101
     */
1102
    public function is_unique($field, $value)
1103
    {
1104
        $this->db->where($field, $value);
1105
        $query = $this->db->get($this->table_name);
1106
1107
        if ($query && $query->num_rows() == 0) {
1108
            return TRUE;
1109
        }
1110
1111
        return FALSE;
1112
1113
    }
1114
1115
    //---------------------------------------------------------------
1116
1117
    /**
1118
     * Adds a field to the protected_attributes array.
1119
     *
1120
     * @param $field
1121
     *
1122
     * @return mixed
1123
     */
1124
    public function protect($field)
1125
    {
1126
        $this->protected_attributes[] = $field;
1127
1128
        return $this;
1129
    }
1130
1131
    //--------------------------------------------------------------------
1132
1133
    /**
1134
     * Get the field names for this model's table.
1135
     *
1136
     * Returns the model's database fields stored in $this->fields
1137
     * if set, else it tries to retrieve the field list from
1138
     * $this->db->list_fields($this->table_name);
1139
     *
1140
     * @return array    Returns the database fields for this model
1141
     */
1142
    public function get_fields()
1143
    {
1144
        if (empty($this->fields)) {
1145
            $this->fields = $this->db->list_fields($this->table_name);
1146
        }
1147
1148
        return $this->fields;
1149
    }
1150
1151
    //--------------------------------------------------------------------
1152
1153
    /**
1154
     * Extracts the model's fields (except the key and those handled by
1155
     * Observers) from the $post_data and returns an array of name => value pairs
1156
     *
1157
     * @param Array $post_data The post data, usually $this->input->post() when called from the controller
1158
     *
1159
     * @return Array    An array of name => value pairs containing the data for the model's fields
1160
     */
1161
    public function prep_data($post_data)
1162
    {
1163
        $data = array();
1164
        $skippedFields = array();
1165
1166
        if (empty($post_data))
1167
        {
1168
            return [];
1169
        }
1170
1171
        // Though the model doesn't support multiple keys well, $this->key
1172
        // could be an array or a string...
1173
        $skippedFields = array_merge($skippedFields, (array)$this->primary_key);
1174
1175
        // Remove any protected attributes
1176
        $skippedFields = array_merge($skippedFields, $this->protected_attributes);
1177
1178
        $fields = $this->get_fields();
1179
1180
        // If the field is the primary key, one of the created/modified/deleted
1181
        // fields, or has not been set in the $post_data, skip it
1182
        foreach ($post_data as $field => $value) {
1183
            if (in_array($field, $skippedFields) ||
1184
                ! in_array($field, $fields))
1185
            {
1186
                continue;
1187
            }
1188
1189
            $data[$field] = $value;
1190
        }
1191
1192
        return $data;
1193
    }
1194
1195
    //--------------------------------------------------------------------
1196
1197
    /**
1198
     * Returns the last query string, if available. Simply a wrapper for
1199
     * CodeIgniter's database method of the same name.
1200
     *
1201
     * @return string
1202
     */
1203
    public function last_query ()
1204
    {
1205
        return $this->db->last_query();
1206
    }
1207
1208
    //--------------------------------------------------------------------
1209
1210
    /**
1211
     * Returns the elapsed time for the last query that was executed, if
1212
     * available, or NULL if not available, like if debug mode is off.
1213
     *
1214
     * @return mixed
1215
     */
1216
    public function last_query_time ()
1217
    {
1218
        $times = $this->db->query_times;
1219
1220
        if (! is_array($this->db->query_times) || ! count($this->db->query_times))
1221
        {
1222
            return null;
1223
        }
1224
1225
        return end($times);
1226
    }
1227
1228
    //--------------------------------------------------------------------
1229
1230
    //--------------------------------------------------------------------
1231
    // Observers
1232
    //--------------------------------------------------------------------
1233
1234
    /**
1235
     * Sets the created on date for the object based on the
1236
     * current date/time and date_format. Will not overwrite existing.
1237
     *
1238
     * @param array $row The array of data to be inserted
1239
     *
1240
     * @return array
1241
     */
1242 View Code Duplication
    public function created_on($row)
1243
    {
1244
        if (empty($row['fields']))
1245
        {
1246
            return null;
1247
        }
1248
1249
        $row = $row['fields'];
1250
1251
        // Created_on
1252
        if (! array_key_exists($this->created_field, $row))
1253
        {
1254
            $row[$this->created_field] = $this->set_date();
1255
        }
1256
1257
        // Created by
1258
        if ($this->log_user && ! array_key_exists($this->created_by_field, $row) && is_object($this->authenticate))
1259
        {
1260
            // If you're here because of an error with $this->authenticate
1261
            // not being available, it's likely due to you not using
1262
            // the AuthTrait and/or setting log_user after model is instantiated.
1263
            $row[$this->created_by_field] = (int)$this->authenticate->id();
1264
        }
1265
1266
        return $row;
1267
    } // end created_on()
1268
1269
    //--------------------------------------------------------------------
1270
1271
    /**
1272
     * Sets the modified_on date for the object based on the
1273
     * current date/time and date_format. Will not overwrite existing.
1274
     *
1275
     * @param array $row The array of data to be inserted
1276
     *
1277
     * @return array
1278
     */
1279 View Code Duplication
    public function modified_on($row)
1280
    {
1281
        if (empty($row['fields']))
1282
        {
1283
            return null;
1284
        }
1285
1286
        $row = $row['fields'];
1287
1288
        if (is_array($row) && ! array_key_exists($this->modified_field, $row))
1289
        {
1290
            $row[$this->modified_field] = $this->set_date();
1291
        }
1292
1293
        // Modified by
1294
        if ($this->log_user && ! array_key_exists($this->modified_by_field, $row) && is_object($this->authenticate))
1295
        {
1296
            // If you're here because of an error with $this->authenticate
1297
            // not being available, it's likely due to you not using
1298
            // the AuthTrait and/or setting log_user after model is instantiated.
1299
            $row[$this->modified_by_field] = $this->authenticate->id();
1300
        }
1301
1302
        return $row;
1303
    }
1304
1305
    //--------------------------------------------------------------------
1306
1307
    //--------------------------------------------------------------------
1308
    // Internal Methods
1309
    //--------------------------------------------------------------------
1310
1311
    /**
1312
     * Set WHERE parameters
1313
     */
1314
    protected function _set_where($params)
1315
    {
1316
        if (count($params) == 1) {
1317
            $this->db->where($params[0]);
1318
        } else {
1319
            $this->db->where($params[0], $params[1]);
1320
        }
1321
    }
1322
1323
    //--------------------------------------------------------------------
1324
1325
    /**
1326
     * Triggers a model-specific event and call each of it's observers.
1327
     *
1328
     * @param string $event The name of the event to trigger
1329
     * @param mixed $data The data to be passed to the callback functions.
1330
     *
1331
     * @return mixed
1332
     */
1333
    public function trigger($event, $data = false)
1334
    {
1335
        if (! isset($this->$event) || ! is_array($this->$event))
1336
        {
1337
            if (isset($data['fields']))
1338
            {
1339
                return $data['fields'];
1340
            }
1341
1342
            return $data;
1343
        }
1344
1345
        foreach ($this->$event as $method)
1346
        {
1347
            if (strpos($method, '('))
1348
            {
1349
                preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches);
1350
                $this->callback_parameters = explode(',', $matches[3]);
1351
            }
1352
1353
            $data = call_user_func_array(array($this, $method), array($data));
1354
        }
1355
1356
        // In case no method called or method returned
1357
        // the entire data array, we typically just need the $fields
1358
        if (isset($data['fields']))
1359
        {
1360
            return $data['fields'];
1361
        }
1362
1363
        // A few methods might need to return 'ids'
1364
        if (isset($data['ids']))
1365
        {
1366
            return $data['ids'];
1367
        }
1368
1369
        return $data;
1370
    }
1371
1372
    //--------------------------------------------------------------------
1373
1374
    /**
1375
     * Validates the data passed into it based upon the form_validation rules
1376
     * setup in the $this->validate property.
1377
     *
1378
     * If $type == 'insert', any additional rules in the class var $insert_validate_rules
1379
     * for that field will be added to the rules.
1380
     *
1381
     * @param  array $data An array of validation rules
1382
     * @param  string $type Either 'update' or 'insert'.
1383
     * @return array/bool       The original data or FALSE
1384
     */
1385
    public function validate($data, $type = 'update', $skip_validation = null)
1386
    {
1387
        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
1388
1389
        if ($skip_validation) {
1390
            return $data;
1391
        }
1392
1393
        // We need the database to be loaded up at this point in case
1394
        // we want to use callbacks that hit the database.
1395
        if (empty($this->db))
1396
        {
1397
            $this->load->database();
1398
        }
1399
1400
        if (!empty($this->validation_rules)) {
1401
            $this->form_validation->set_data($data);
1402
1403
            if (is_array($this->validation_rules)) {
1404
                // Any insert additions?
1405
                if ($type == 'insert'
1406
                    && !empty($this->insert_validate_rules)
1407
                    && is_array($this->insert_validate_rules)
1408
                ) {
1409
                    foreach ($this->validation_rules as &$row) {
1410
                        if (isset($this->insert_validate_rules[$row['field']])) {
1411
                            $row ['rules'] .= '|' . $this->insert_validate_rules[$row['field']];
1412
                        }
1413
                    }
1414
                }
1415
1416
                $this->form_validation->set_rules($this->validation_rules);
1417
1418
                if ($this->form_validation->run('', $this) === TRUE) {
1419
                    return $data;
1420
                } else {
1421
                    return FALSE;
1422
                }
1423
            } else {
1424
                if ($this->form_validation->run($this->validate, $this) === TRUE) {
1425
                    return $data;
1426
                } else {
1427
                    return FALSE;
1428
                }
1429
            }
1430
        } else {
1431
            return $data;
1432
        }
1433
    }
1434
1435
    //--------------------------------------------------------------------
1436
1437
    /**
1438
     * Protect attributes by removing them from $row array. Useful for
1439
     * removing id, or submit buttons names if you simply throw your $_POST
1440
     * array at your model. :)
1441
     *
1442
     * @param object /array $row The value pair item to remove.
1443
     */
1444
    public function protect_attributes($row)
1445
    {
1446
        foreach ($this->protected_attributes as $attr) {
1447
            if (is_object($row)) {
1448
                unset($row->$attr);
1449
            } else {
1450
                unset($row[$attr]);
1451
            }
1452
        }
1453
1454
        return $row;
1455
    }
1456
1457
    //--------------------------------------------------------------------
1458
1459
    /**
1460
     * A utility function to allow child models to use the type of
1461
     * date/time format that they prefer. This is primarily used for
1462
     * setting created_on and modified_on values, but can be used by
1463
     * inheriting classes.
1464
     *
1465
     * The available time formats are:
1466
     * * 'int'      - Stores the date as an integer timestamp.
1467
     * * 'datetime' - Stores the date and time in the SQL datetime format.
1468
     * * 'date'     - Stores teh date (only) in the SQL date format.
1469
     *
1470
     * @param mixed $user_date An optional PHP timestamp to be converted.
1471
     *
1472
     * @access protected
1473
     *
1474
     * @return int|null|string The current/user time converted to the proper format.
1475
     */
1476
    protected function set_date($user_date = NULL)
1477
    {
1478
        $curr_date = !empty($user_date) ? $user_date : time();
1479
1480
        switch ($this->date_format) {
1481
            case 'int':
1482
                return $curr_date;
1483
                break;
1484
            case 'datetime':
1485
                return date('Y-m-d H:i:s', $curr_date);
1486
                break;
1487
            case 'date':
1488
                return date('Y-m-d', $curr_date);
1489
                break;
1490
        }
1491
1492
    }//end set_date()
1493
1494
    //--------------------------------------------------------------------
1495
1496
    /**
1497
     * Returns an array containing the 'code' and 'message' of the
1498
     * database's error, as provided by CI's database drivers.
1499
     *
1500
     * @return mixed
1501
     */
1502
    public function error($db_array_only=false)
1503
    {
1504
        // Send any validation errors if we have any.
1505
        if (function_exists('validation_errors') && validation_errors() && ! $db_array_only)
1506
        {
1507
            return validation_errors();
1508
        }
1509
1510
        // No validation errors? Return the db error.
1511
        $error = $this->db->error();
1512
1513
        if ($db_array_only)
1514
        {
1515
            return $error;
1516
        }
1517
1518
        if (! empty($error['code']))
1519
        {
1520
            return "Database Error {$error['code']}: {$error['message']}.";
1521
        }
1522
1523
        // No errors found.
1524
        return '';
1525
    }
1526
1527
    //--------------------------------------------------------------------
1528
1529
    //--------------------------------------------------------------------
1530
    // Magic Methods
1531
    //--------------------------------------------------------------------
1532
1533
    /**
1534
     * __get magic
1535
     *
1536
     * Allows models to access CI's loaded classes using the same
1537
     * syntax as controllers.
1538
     *
1539
     * This is the same as what CI's model uses, but we keep it
1540
     * here since that's the ONLY thing that CI's model does.
1541
     *
1542
     * @param    string $key
1543
     */
1544
    public function __get($key)
1545
    {
1546
        // Give them first crack at any protected class vars
1547
        if (isset($this->$key))
1548
        {
1549
            return $this->$key;
1550
        }
1551
1552
        // Debugging note:
1553
        //	If you're here because you're getting an error message
1554
        //	saying 'Undefined Property: system/core/Model.php', it's
1555
        //	most likely a typo in your model code.
1556
        return get_instance()->$key;
1557
    }
1558
1559
    //--------------------------------------------------------------------
1560
1561
    /**
1562
     * Provide direct access to any of CodeIgniter's DB methods but
1563
     * make it look like it's part of the class, purely for convenience.
1564
     *
1565
     * @param $name
1566
     * @param $params
1567
     */
1568
    public function __call($name, $params)
1569
    {
1570
        if (method_exists($this->db, $name))
1571
        {
1572
            call_user_func_array([$this->db, $name], $params);
1573
            return $this;
1574
        }
1575
    }
1576
1577
    //--------------------------------------------------------------------
1578
1579
1580
}
1581