blob: d27d3dc1ea744aaa9864c8a334c02212367bd008 [file] [log] [blame]
adminac94f382006-09-24 20:28:12 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
admine334c472006-10-21 19:44:22 +000010 * @license http://www.codeignitor.com/user_guide/license.html
adminac94f382006-09-24 20:28:12 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
admine334c472006-10-21 19:44:22 +000015
adminac94f382006-09-24 20:28:12 +000016// ------------------------------------------------------------------------
17
18/**
19 * Active Record Class
admine334c472006-10-21 19:44:22 +000020 *
adminac94f382006-09-24 20:28:12 +000021 * This is the platform-independent base Active Record implementation class.
22 *
23 * @package CodeIgniter
24 * @subpackage Drivers
25 * @category Database
26 * @author Rick Ellis
27 * @link http://www.codeigniter.com/user_guide/database/
28 */
29class CI_DB_active_record extends CI_DB_driver {
30
31 var $ar_select = array();
32 var $ar_distinct = FALSE;
33 var $ar_from = array();
34 var $ar_join = array();
35 var $ar_where = array();
36 var $ar_like = array();
37 var $ar_groupby = array();
38 var $ar_having = array();
39 var $ar_limit = FALSE;
40 var $ar_offset = FALSE;
41 var $ar_order = FALSE;
42 var $ar_orderby = array();
43 var $ar_set = array();
44
45
46 /**
47 * Select
48 *
49 * Generates the SELECT portion of the query
50 *
51 * @access public
52 * @param string
53 * @return object
54 */
55 function select($select = '*')
56 {
57 if (is_string($select))
58 {
59 $select = explode(',', $select);
60 }
61
62 foreach ($select as $val)
63 {
64 $val = trim($val);
65
66 if ($val != '')
67 $this->ar_select[] = $val;
68 }
69 return $this;
70 }
71
72 // --------------------------------------------------------------------
73
74 /**
75 * DISTINCT
76 *
77 * Sets a flag which tells the query string compiler to add DISTINCT
78 *
79 * @access public
80 * @param bool
81 * @return object
82 */
83 function distinct($val = TRUE)
84 {
85 $this->ar_distinct = (is_bool($val)) ? $val : TRUE;
86 return $this;
87 }
88
89 // --------------------------------------------------------------------
90
91 /**
92 * From
93 *
94 * Generates the FROM portion of the query
95 *
96 * @access public
97 * @param mixed can be a string or array
98 * @return object
99 */
100 function from($from)
101 {
102 foreach ((array)$from as $val)
103 {
104 $this->ar_from[] = $this->dbprefix.$val;
105 }
106 return $this;
107 }
108
109 // --------------------------------------------------------------------
110
111 /**
112 * Join
113 *
114 * Generates the JOIN portion of the query
115 *
116 * @access public
117 * @param string
118 * @param string the join condition
119 * @param string the type of join
120 * @return object
121 */
122 function join($table, $cond, $type = '')
123 {
124 if ($type != '')
125 {
126 $type = strtoupper(trim($type));
127
adminee54c112006-09-28 17:13:38 +0000128 if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
adminac94f382006-09-24 20:28:12 +0000129 {
130 $type = '';
131 }
132 else
133 {
134 $type .= ' ';
135 }
136 }
Rick Ellisbb433722007-02-05 22:32:49 +0000137
138 // If a DB prefix is used we might need to add it to the column names
139 if ($this->dbprefix)
140 {
141 // First we remove any existing prefixes in the condition to avoid duplicates
142 $cond = preg_replace('|('.$this->dbprefix.')([\w\.]+)([\W\s]+)|', "$2$3", $cond);
143
144 // Next we add the prefixes to the condition
145 $cond = preg_replace('|([\w\.]+)([\W\s]+)(.+)|', $this->dbprefix . "$1$2" . $this->dbprefix . "$3", $cond);
146 }
147
admin402d1d52006-09-27 01:54:14 +0000148 $this->ar_join[] = $type.'JOIN '.$this->dbprefix.$table.' ON '.$cond;
adminac94f382006-09-24 20:28:12 +0000149 return $this;
150 }
151
152 // --------------------------------------------------------------------
153
154 /**
155 * Where
156 *
157 * Generates the WHERE portion of the query. Separates
158 * multiple calls with AND
159 *
160 * @access public
161 * @param mixed
162 * @param mixed
163 * @return object
164 */
165 function where($key, $value = NULL)
166 {
167 return $this->_where($key, $value, 'AND ');
168 }
169
170 // --------------------------------------------------------------------
171
172 /**
173 * OR Where
174 *
175 * Generates the WHERE portion of the query. Separates
176 * multiple calls with OR
177 *
178 * @access public
179 * @param mixed
180 * @param mixed
181 * @return object
182 */
183 function orwhere($key, $value = NULL)
184 {
185 return $this->_where($key, $value, 'OR ');
186 }
187
188 // --------------------------------------------------------------------
189
190 /**
191 * Where
192 *
193 * Called by where() or orwhere()
194 *
195 * @access private
196 * @param mixed
197 * @param mixed
198 * @param string
199 * @return object
200 */
201 function _where($key, $value = NULL, $type = 'AND ')
202 {
203 if ( ! is_array($key))
204 {
205 $key = array($key => $value);
206 }
207
208 foreach ($key as $k => $v)
209 {
210 $prefix = (count($this->ar_where) == 0) ? '' : $type;
211
212 if ( ! is_null($v))
213 {
214 if ( ! $this->_has_operator($k))
215 {
216 $k .= ' =';
217 }
218
219 $v = ' '.$this->escape($v);
220 }
221
222 $this->ar_where[] = $prefix.$k.$v;
223 }
224 return $this;
225 }
226
227
228
229 // --------------------------------------------------------------------
230
231 /**
232 * Like
233 *
234 * Generates a %LIKE% portion of the query. Separates
235 * multiple calls with AND
236 *
237 * @access public
238 * @param mixed
239 * @param mixed
240 * @return object
241 */
242 function like($field, $match = '')
243 {
244 return $this->_like($field, $match, 'AND ');
245 }
246
247 // --------------------------------------------------------------------
248
249 /**
250 * OR Like
251 *
252 * Generates a %LIKE% portion of the query. Separates
253 * multiple calls with OR
254 *
255 * @access public
256 * @param mixed
257 * @param mixed
258 * @return object
259 */
260 function orlike($field, $match = '')
261 {
262 return $this->_like($field, $match, 'OR ');
263 }
264
265 // --------------------------------------------------------------------
266
267 /**
268 * Like
269 *
270 * Called by like() or orlike()
271 *
272 * @access private
273 * @param mixed
274 * @param mixed
275 * @param string
276 * @return object
277 */
278 function _like($field, $match = '', $type = 'AND ')
279 {
280 if ( ! is_array($field))
281 {
282 $field = array($field => $match);
283 }
284
285 foreach ($field as $k => $v)
286 {
287 $prefix = (count($this->ar_like) == 0) ? '' : $type;
288
289 $v = $this->escape_str($v);
290
291 $this->ar_like[] = $prefix." $k LIKE '%{$v}%'";
292 }
293 return $this;
294 }
295
296 // --------------------------------------------------------------------
297
298 /**
299 * GROUP BY
300 *
301 * @access public
302 * @param string
303 * @return object
304 */
305 function groupby($by)
306 {
307 if (is_string($by))
308 {
309 $by = explode(',', $by);
310 }
311
312 foreach ($by as $val)
313 {
314 $val = trim($val);
315
316 if ($val != '')
317 $this->ar_groupby[] = $val;
318 }
319 return $this;
320 }
321
322 // --------------------------------------------------------------------
323
324 /**
325 * Sets the HAVING value
326 *
327 * Separates multiple calls with AND
328 *
329 * @access public
330 * @param string
331 * @param string
332 * @return object
333 */
334 function having($key, $value = '')
335 {
336 return $this->_having($key, $value, 'AND ');
337 }
338
339 // --------------------------------------------------------------------
340
341 /**
342 * Sets the OR HAVING value
343 *
344 * Separates multiple calls with OR
345 *
346 * @access public
347 * @param string
348 * @param string
349 * @return object
350 */
351 function orhaving($key, $value = '')
352 {
353 return $this->_having($key, $value, 'OR ');
354 }
355
356 // --------------------------------------------------------------------
357
358 /**
359 * Sets the HAVING values
360 *
361 * Called by having() or orhaving()
362 *
363 * @access private
364 * @param string
365 * @param string
366 * @return object
367 */
368 function _having($key, $value = '', $type = 'AND ')
369 {
370 if ( ! is_array($key))
371 {
372 $key = array($key => $value);
373 }
374
375 foreach ($key as $k => $v)
376 {
377 $prefix = (count($this->ar_having) == 0) ? '' : $type;
378
379 if ($v != '')
380 {
381 $v = ' '.$this->escape($v);
382 }
383
384 $this->ar_having[] = $prefix.$k.$v;
385 }
386 return $this;
387 }
388
389 // --------------------------------------------------------------------
390
391 /**
392 * Sets the ORDER BY value
393 *
394 * @access public
395 * @param string
396 * @param string direction: asc or desc
397 * @return object
398 */
399 function orderby($orderby, $direction = '')
400 {
401 if (trim($direction) != '')
402 {
adminee54c112006-09-28 17:13:38 +0000403 $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC', 'RAND()'), TRUE)) ? ' '.$direction : ' ASC';
adminac94f382006-09-24 20:28:12 +0000404 }
405
406 $this->ar_orderby[] = $orderby.$direction;
407 return $this;
408 }
409
410 // --------------------------------------------------------------------
411
412 /**
413 * Sets the LIMIT value
414 *
415 * @access public
416 * @param integer the limit value
417 * @param integer the offset value
418 * @return object
419 */
420 function limit($value, $offset = '')
421 {
422 $this->ar_limit = $value;
423
424 if ($offset != '')
425 $this->ar_offset = $offset;
426
427 return $this;
428 }
429
430 // --------------------------------------------------------------------
431
432 /**
433 * Sets the OFFSET value
434 *
435 * @access public
436 * @param integer the offset value
437 * @return object
438 */
439 function offset($value)
440 {
441 $this->ar_offset = $value;
442 return $this;
443 }
444
445 // --------------------------------------------------------------------
446
447 /**
448 * The "set" function. Allows key/value pairs to be set for inserting or updating
449 *
450 * @access public
451 * @param mixed
452 * @param string
453 * @return object
454 */
455 function set($key, $value = '')
456 {
457 $key = $this->_object_to_array($key);
458
459 if ( ! is_array($key))
460 {
461 $key = array($key => $value);
462 }
463
464 foreach ($key as $k => $v)
465 {
466 $this->ar_set[$k] = $this->escape($v);
467 }
468
469 return $this;
470 }
471
472 // --------------------------------------------------------------------
473
474 /**
475 * Get
476 *
477 * Compiles the select statement based on the other functions called
478 * and runs the query
479 *
480 * @access public
481 * @param string the limit clause
482 * @param string the offset clause
483 * @return object
484 */
485 function get($table = '', $limit = null, $offset = null)
486 {
487 if ($table != '')
488 {
489 $this->from($table);
490 }
491
492 if ( ! is_null($limit))
493 {
494 $this->limit($limit, $offset);
495 }
496
497 $sql = $this->_compile_select();
498
adminc50747c2006-11-03 17:17:02 +0000499 $result = $this->query($sql);
adminac94f382006-09-24 20:28:12 +0000500 $this->_reset_select();
adminc50747c2006-11-03 17:17:02 +0000501 return $result;
adminac94f382006-09-24 20:28:12 +0000502 }
503
504 // --------------------------------------------------------------------
505
506 /**
507 * GetWhere
508 *
509 * Allows the where clause, limit and offset to be added directly
510 *
511 * @access public
512 * @param string the where clause
513 * @param string the limit clause
514 * @param string the offset clause
515 * @return object
516 */
517 function getwhere($table = '', $where = null, $limit = null, $offset = null)
518 {
519 if ($table != '')
520 {
521 $this->from($table);
522 }
523
524 if ( ! is_null($where))
525 {
526 $this->where($where);
527 }
528
529 if ( ! is_null($limit))
530 {
531 $this->limit($limit, $offset);
532 }
533
534 $sql = $this->_compile_select();
535
adminc50747c2006-11-03 17:17:02 +0000536 $result = $this->query($sql);
adminac94f382006-09-24 20:28:12 +0000537 $this->_reset_select();
adminc50747c2006-11-03 17:17:02 +0000538 return $result;
adminac94f382006-09-24 20:28:12 +0000539 }
540
541 // --------------------------------------------------------------------
542
543 /**
544 * Insert
545 *
546 * Compiles an insert string and runs the query
547 *
548 * @access public
549 * @param string the table to retrieve the results from
550 * @param array an associative array of insert values
551 * @return object
552 */
553 function insert($table = '', $set = NULL)
554 {
555 if ( ! is_null($set))
556 {
557 $this->set($set);
558 }
559
560 if (count($this->ar_set) == 0)
561 {
admine334c472006-10-21 19:44:22 +0000562 if ($this->db_debug)
563 {
adminac94f382006-09-24 20:28:12 +0000564 return $this->display_error('db_must_use_set');
admine334c472006-10-21 19:44:22 +0000565 }
566 return FALSE;
adminac94f382006-09-24 20:28:12 +0000567 }
568
569 if ($table == '')
570 {
571 if ( ! isset($this->ar_from[0]))
572 {
573 if ($this->db_debug)
574 {
575 return $this->display_error('db_must_set_table');
576 }
577 return FALSE;
578 }
579
580 $table = $this->ar_from[0];
581 }
582
583 $sql = $this->_insert($this->dbprefix.$table, array_keys($this->ar_set), array_values($this->ar_set));
584
585 $this->_reset_write();
586 return $this->query($sql);
587 }
588
589 // --------------------------------------------------------------------
590
591 /**
592 * Update
593 *
594 * Compiles an update string and runs the query
595 *
596 * @access public
597 * @param string the table to retrieve the results from
598 * @param array an associative array of update values
599 * @param mixed the where clause
600 * @return object
601 */
602 function update($table = '', $set = NULL, $where = null)
603 {
604 if ( ! is_null($set))
605 {
606 $this->set($set);
607 }
608
609 if (count($this->ar_set) == 0)
610 {
admine334c472006-10-21 19:44:22 +0000611 if ($this->db_debug)
612 {
adminac94f382006-09-24 20:28:12 +0000613 return $this->display_error('db_must_use_set');
admine334c472006-10-21 19:44:22 +0000614 }
615 return FALSE;
adminac94f382006-09-24 20:28:12 +0000616 }
617
618 if ($table == '')
619 {
620 if ( ! isset($this->ar_from[0]))
621 {
622 if ($this->db_debug)
623 {
624 return $this->display_error('db_must_set_table');
625 }
626 return FALSE;
627 }
628
629 $table = $this->ar_from[0];
630 }
631
632 if ($where != null)
633 {
634 $this->where($where);
635 }
636
637 $sql = $this->_update($this->dbprefix.$table, $this->ar_set, $this->ar_where);
638
639 $this->_reset_write();
640 return $this->query($sql);
641 }
642
643 // --------------------------------------------------------------------
644
645 /**
646 * Delete
647 *
648 * Compiles a delete string and runs the query
649 *
650 * @access public
651 * @param string the table to retrieve the results from
652 * @param mixed the where clause
653 * @return object
654 */
655 function delete($table = '', $where = '')
656 {
657 if ($table == '')
658 {
659 if ( ! isset($this->ar_from[0]))
660 {
661 if ($this->db_debug)
662 {
663 return $this->display_error('db_must_set_table');
664 }
665 return FALSE;
666 }
667
668 $table = $this->ar_from[0];
669 }
670
671 if ($where != '')
672 {
673 $this->where($where);
674 }
675
676 if (count($this->ar_where) == 0)
677 {
admine334c472006-10-21 19:44:22 +0000678 if ($this->db_debug)
679 {
adminac94f382006-09-24 20:28:12 +0000680 return $this->display_error('db_del_must_use_where');
admine334c472006-10-21 19:44:22 +0000681 }
682 return FALSE;
adminac94f382006-09-24 20:28:12 +0000683 }
684
685 $sql = $this->_delete($this->dbprefix.$table, $this->ar_where);
686
687 $this->_reset_write();
688 return $this->query($sql);
689 }
690
691 // --------------------------------------------------------------------
692
693 /**
admine334c472006-10-21 19:44:22 +0000694 * Use Table - DEPRECATED
adminac94f382006-09-24 20:28:12 +0000695 *
696 * @deprecated use $this->db->from instead
697 */
698 function use_table($table)
699 {
700 return $this->from($table);
701 return $this;
702 }
703
704 // --------------------------------------------------------------------
705
706 /**
707 * ORDER BY - DEPRECATED
708 *
709 * @deprecated use $this->db->orderby() instead
710 */
711 function order_by($orderby, $direction = '')
712 {
713 return $this->orderby($orderby, $direction);
714 }
715
716 // --------------------------------------------------------------------
717
718 /**
719 * Tests whether the string has an SQL operator
720 *
721 * @access private
722 * @param string
723 * @return bool
724 */
725 function _has_operator($str)
726 {
727 $str = trim($str);
728 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
729 {
730 return FALSE;
731 }
732
733 return TRUE;
734 }
735
736 // --------------------------------------------------------------------
737
738 /**
739 * Compile the SELECT statement
740 *
admine334c472006-10-21 19:44:22 +0000741 * Generates a query string based on which functions were used.
adminac94f382006-09-24 20:28:12 +0000742 * Should not be called directly. The get() function calls it.
743 *
744 * @access private
745 * @return string
746 */
747 function _compile_select()
748 {
749 $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
750
751 $sql .= (count($this->ar_select) == 0) ? '*' : implode(', ', $this->ar_select);
752
753 if (count($this->ar_from) > 0)
754 {
755 $sql .= "\nFROM ";
756 $sql .= implode(', ', $this->ar_from);
757 }
758
759 if (count($this->ar_join) > 0)
760 {
761 $sql .= "\n";
762 $sql .= implode("\n", $this->ar_join);
763 }
764
765 if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
766 {
767 $sql .= "\nWHERE ";
768 }
769
770 $sql .= implode("\n", $this->ar_where);
771
772 if (count($this->ar_like) > 0)
773 {
774 if (count($this->ar_where) > 0)
775 {
776 $sql .= " AND ";
777 }
778
779 $sql .= implode("\n", $this->ar_like);
780 }
781
782 if (count($this->ar_groupby) > 0)
783 {
784 $sql .= "\nGROUP BY ";
785 $sql .= implode(', ', $this->ar_groupby);
786 }
787
788 if (count($this->ar_having) > 0)
789 {
790 $sql .= "\nHAVING ";
791 $sql .= implode("\n", $this->ar_having);
792 }
793
794 if (count($this->ar_orderby) > 0)
795 {
796 $sql .= "\nORDER BY ";
797 $sql .= implode(', ', $this->ar_orderby);
798
799 if ($this->ar_order !== FALSE)
800 {
801 $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
802 }
803 }
804
805 if (is_numeric($this->ar_limit))
806 {
807 $sql .= "\n";
808 $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
809 }
810
811 return $sql;
812 }
813
814 // --------------------------------------------------------------------
815
816 /**
817 * Object to Array
818 *
adminfafe28b2006-10-21 19:08:17 +0000819 * Takes an object as input and converts the class variables to array key/vals
adminac94f382006-09-24 20:28:12 +0000820 *
821 * @access public
822 * @param object
823 * @return array
824 */
825 function _object_to_array($object)
826 {
827 if ( ! is_object($object))
828 {
829 return $object;
830 }
831
832 $array = array();
833 foreach (get_object_vars($object) as $key => $val)
834 {
835 if ( ! is_object($val) AND ! is_array($val))
836 {
837 $array[$key] = $val;
838 }
839 }
840
841 return $array;
842 }
843
844 // --------------------------------------------------------------------
845
846 /**
847 * Resets the active record values. Called by the get() function
848 *
849 * @access private
850 * @return void
851 */
852 function _reset_select()
853 {
854 $this->ar_select = array();
855 $this->ar_distinct = FALSE;
856 $this->ar_from = array();
857 $this->ar_join = array();
858 $this->ar_where = array();
859 $this->ar_like = array();
860 $this->ar_groupby = array();
861 $this->ar_having = array();
862 $this->ar_limit = FALSE;
863 $this->ar_offset = FALSE;
864 $this->ar_order = FALSE;
865 $this->ar_orderby = array();
866 }
867
868 // --------------------------------------------------------------------
869
870 /**
871 * Resets the active record "write" values.
872 *
873 * Called by the insert() or update() functions
874 *
875 * @access private
876 * @return void
877 */
878 function _reset_write()
879 {
880 $this->ar_set = array();
881 $this->ar_from = array();
882 $this->ar_where = array();
883 }
884
885}
886
887?>