blob: 6a991a2edb65a9446f0e8977b9e353aabc5d416b [file] [log] [blame]
Derek Allard09de1852007-02-14 01:35:56 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
Derek Allardd2df9bc2007-04-15 17:41:17 +00003 * CodeIgniter
Derek Allard09de1852007-02-14 01:35:56 +00004 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
Derek Allardd2df9bc2007-04-15 17:41:17 +00009 * @copyright Copyright (c) 2006, EllisLab, Inc.
Derek Allard6838f002007-10-04 19:29:59 +000010 * @license http://www.codeigniter.com/user_guide/license.html
Derek Allard09de1852007-02-14 01:35:56 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * Active Record Class
20 *
21 * 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
128 if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
129 {
130 $type = '';
131 }
132 else
133 {
134 $type .= ' ';
135 }
136 }
137
138 if ($this->dbprefix)
139 {
140 $cond = preg_replace('|([\w\.]+)([\W\s]+)(.+)|', $this->dbprefix . "$1$2" . $this->dbprefix . "$3", $cond);
141 }
142
143 // If a DB prefix is used we might need to add it to the column names
144 if ($this->dbprefix)
145 {
146 // First we remove any existing prefixes in the condition to avoid duplicates
147 $cond = preg_replace('|('.$this->dbprefix.')([\w\.]+)([\W\s]+)|', "$2$3", $cond);
148
149 // Next we add the prefixes to the condition
150 $cond = preg_replace('|([\w\.]+)([\W\s]+)(.+)|', $this->dbprefix . "$1$2" . $this->dbprefix . "$3", $cond);
151 }
152
153 $this->ar_join[] = $type.'JOIN '.$this->dbprefix.$table.' ON '.$cond;
154 return $this;
155 }
156
157 // --------------------------------------------------------------------
158
159 /**
160 * Where
161 *
162 * Generates the WHERE portion of the query. Separates
163 * multiple calls with AND
164 *
165 * @access public
166 * @param mixed
167 * @param mixed
168 * @return object
169 */
170 function where($key, $value = NULL)
171 {
172 return $this->_where($key, $value, 'AND ');
173 }
174
175 // --------------------------------------------------------------------
176
177 /**
178 * OR Where
179 *
180 * Generates the WHERE portion of the query. Separates
181 * multiple calls with OR
182 *
183 * @access public
184 * @param mixed
185 * @param mixed
186 * @return object
187 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000188 function or_where($key, $value = NULL)
Derek Allard09de1852007-02-14 01:35:56 +0000189 {
190 return $this->_where($key, $value, 'OR ');
191 }
Derek Allard218e2bc2007-12-17 21:18:14 +0000192
193 // --------------------------------------------------------------------
194
195 /**
196 * orwhere() is an alias of or_where()
197 * this function is here for backwards compatibility, as
198 * orwhere() has been deprecated
199 */
200 function orwhere($key, $value = NULL)
201 {
202 return $this->or_where($key, $value);
203 }
Derek Allard09de1852007-02-14 01:35:56 +0000204
205 // --------------------------------------------------------------------
206
207 /**
208 * Where
209 *
210 * Called by where() or orwhere()
211 *
212 * @access private
213 * @param mixed
214 * @param mixed
215 * @param string
216 * @return object
217 */
218 function _where($key, $value = NULL, $type = 'AND ')
219 {
220 if ( ! is_array($key))
221 {
222 $key = array($key => $value);
223 }
224
225 foreach ($key as $k => $v)
226 {
227 $prefix = (count($this->ar_where) == 0) ? '' : $type;
228
229 if ( ! is_null($v))
230 {
231 if ( ! $this->_has_operator($k))
232 {
233 $k .= ' =';
234 }
235
236 $v = ' '.$this->escape($v);
237 }
238
239 $this->ar_where[] = $prefix.$k.$v;
240 }
241 return $this;
242 }
243
244
245
246 // --------------------------------------------------------------------
247
248 /**
249 * Like
250 *
251 * Generates a %LIKE% portion of the query. Separates
252 * multiple calls with AND
253 *
254 * @access public
255 * @param mixed
256 * @param mixed
257 * @return object
258 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000259 function like($field, $match = '', $side = 'both')
Derek Allard09de1852007-02-14 01:35:56 +0000260 {
Derek Allard218e2bc2007-12-17 21:18:14 +0000261 return $this->_like($field, $match, 'AND ', $side);
Derek Allard09de1852007-02-14 01:35:56 +0000262 }
263
264 // --------------------------------------------------------------------
265
266 /**
267 * OR Like
268 *
269 * Generates a %LIKE% portion of the query. Separates
270 * multiple calls with OR
271 *
272 * @access public
273 * @param mixed
274 * @param mixed
275 * @return object
276 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000277 function or_like($field, $match = '', $side = 'both')
Derek Allard09de1852007-02-14 01:35:56 +0000278 {
Derek Allard218e2bc2007-12-17 21:18:14 +0000279 return $this->_like($field, $match, 'OR ', $side);
280 }
281
282 // --------------------------------------------------------------------
283
284 /**
285 * orlike() is an alias of or_like()
286 * this function is here for backwards compatibility, as
287 * orlike() has been deprecated
288 */
289 function orlike($field, $match = '', $side = 'both')
290 {
291 return $this->orlike($field, $match, $side);
Derek Allard09de1852007-02-14 01:35:56 +0000292 }
293
294 // --------------------------------------------------------------------
295
296 /**
297 * Like
298 *
299 * Called by like() or orlike()
300 *
301 * @access private
302 * @param mixed
303 * @param mixed
304 * @param string
305 * @return object
306 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000307 function _like($field, $match = '', $type = 'AND ', $side = 'both')
Derek Allard09de1852007-02-14 01:35:56 +0000308 {
309 if ( ! is_array($field))
310 {
311 $field = array($field => $match);
312 }
313
314 foreach ($field as $k => $v)
315 {
316 $prefix = (count($this->ar_like) == 0) ? '' : $type;
317
318 $v = $this->escape_str($v);
Derek Allard218e2bc2007-12-17 21:18:14 +0000319
320 if ($side == 'before')
321 {
322 $this->ar_like[] = $prefix." $k LIKE '%{$v}'";
323 }
324 elseif ($side == 'after')
325 {
326 $this->ar_like[] = $prefix." $k LIKE '{$v}%'";
327 }
328 else
329 {
330 $this->ar_like[] = $prefix." $k LIKE '%{$v}%'";
331 }
Derek Allard09de1852007-02-14 01:35:56 +0000332 }
333 return $this;
334 }
335
336 // --------------------------------------------------------------------
337
338 /**
339 * GROUP BY
340 *
341 * @access public
342 * @param string
343 * @return object
344 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000345 function group_by($by)
Derek Allard09de1852007-02-14 01:35:56 +0000346 {
347 if (is_string($by))
348 {
349 $by = explode(',', $by);
350 }
351
352 foreach ($by as $val)
353 {
354 $val = trim($val);
355
356 if ($val != '')
357 $this->ar_groupby[] = $val;
358 }
359 return $this;
360 }
Derek Allard218e2bc2007-12-17 21:18:14 +0000361
362 // --------------------------------------------------------------------
363
364 /**
365 * groupby() is an alias of group_by()
366 * this function is here for backwards compatibility, as
367 * groupby() has been deprecated
368 */
369 function groupby($by)
370 {
371 return $this->group_by($by);
372 }
373
Derek Allard09de1852007-02-14 01:35:56 +0000374 // --------------------------------------------------------------------
375
376 /**
377 * Sets the HAVING value
378 *
379 * Separates multiple calls with AND
380 *
381 * @access public
382 * @param string
383 * @param string
384 * @return object
385 */
386 function having($key, $value = '')
387 {
388 return $this->_having($key, $value, 'AND ');
389 }
390
391 // --------------------------------------------------------------------
392
393 /**
394 * Sets the OR HAVING value
395 *
396 * Separates multiple calls with OR
397 *
398 * @access public
399 * @param string
400 * @param string
401 * @return object
402 */
403 function orhaving($key, $value = '')
404 {
405 return $this->_having($key, $value, 'OR ');
406 }
407
408 // --------------------------------------------------------------------
409
410 /**
411 * Sets the HAVING values
412 *
413 * Called by having() or orhaving()
414 *
415 * @access private
416 * @param string
417 * @param string
418 * @return object
419 */
420 function _having($key, $value = '', $type = 'AND ')
421 {
422 if ( ! is_array($key))
423 {
424 $key = array($key => $value);
425 }
426
427 foreach ($key as $k => $v)
428 {
429 $prefix = (count($this->ar_having) == 0) ? '' : $type;
430
431 if ($v != '')
432 {
433 $v = ' '.$this->escape($v);
434 }
435
436 $this->ar_having[] = $prefix.$k.$v;
437 }
438 return $this;
439 }
440
441 // --------------------------------------------------------------------
442
443 /**
444 * Sets the ORDER BY value
445 *
446 * @access public
447 * @param string
448 * @param string direction: asc or desc
449 * @return object
450 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000451 function order_by($orderby, $direction = '')
Derek Allard09de1852007-02-14 01:35:56 +0000452 {
453 if (trim($direction) != '')
454 {
Derek Allard92782492007-08-10 11:26:01 +0000455 $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
Derek Allard09de1852007-02-14 01:35:56 +0000456 }
457
458 $this->ar_orderby[] = $orderby.$direction;
459 return $this;
460 }
Derek Allard218e2bc2007-12-17 21:18:14 +0000461 // --------------------------------------------------------------------
462
463 /**
464 * orderby() is an alias of order_by()
465 * this function is here for backwards compatibility, as
466 * orderby() has been deprecated
467 */
468 function orderby($orderby, $direction = '')
469 {
470 return $this->order_by($orderby, $direction);
471 }
Derek Allard09de1852007-02-14 01:35:56 +0000472 // --------------------------------------------------------------------
473
474 /**
475 * Sets the LIMIT value
476 *
477 * @access public
478 * @param integer the limit value
479 * @param integer the offset value
480 * @return object
481 */
482 function limit($value, $offset = '')
483 {
484 $this->ar_limit = $value;
485
486 if ($offset != '')
487 $this->ar_offset = $offset;
488
489 return $this;
490 }
491
492 // --------------------------------------------------------------------
493
494 /**
495 * Sets the OFFSET value
496 *
497 * @access public
498 * @param integer the offset value
499 * @return object
500 */
501 function offset($value)
502 {
503 $this->ar_offset = $value;
504 return $this;
505 }
506
507 // --------------------------------------------------------------------
508
509 /**
510 * The "set" function. Allows key/value pairs to be set for inserting or updating
511 *
512 * @access public
513 * @param mixed
514 * @param string
515 * @return object
516 */
517 function set($key, $value = '')
518 {
519 $key = $this->_object_to_array($key);
520
521 if ( ! is_array($key))
522 {
523 $key = array($key => $value);
524 }
525
526 foreach ($key as $k => $v)
527 {
528 $this->ar_set[$k] = $this->escape($v);
529 }
530
531 return $this;
532 }
533
534 // --------------------------------------------------------------------
535
536 /**
537 * Get
538 *
539 * Compiles the select statement based on the other functions called
540 * and runs the query
541 *
542 * @access public
543 * @param string the limit clause
544 * @param string the offset clause
545 * @return object
546 */
547 function get($table = '', $limit = null, $offset = null)
548 {
549 if ($table != '')
550 {
551 $this->from($table);
552 }
553
554 if ( ! is_null($limit))
555 {
556 $this->limit($limit, $offset);
557 }
558
559 $sql = $this->_compile_select();
560
561 $result = $this->query($sql);
562 $this->_reset_select();
563 return $result;
564 }
565
566 // --------------------------------------------------------------------
567
568 /**
Derek Allard218e2bc2007-12-17 21:18:14 +0000569 * Get_Where
Derek Allard09de1852007-02-14 01:35:56 +0000570 *
571 * Allows the where clause, limit and offset to be added directly
572 *
573 * @access public
574 * @param string the where clause
575 * @param string the limit clause
576 * @param string the offset clause
577 * @return object
578 */
Derek Allard218e2bc2007-12-17 21:18:14 +0000579 function get_where($table = '', $where = null, $limit = null, $offset = null)
Derek Allard09de1852007-02-14 01:35:56 +0000580 {
581 if ($table != '')
582 {
583 $this->from($table);
584 }
585
586 if ( ! is_null($where))
587 {
588 $this->where($where);
589 }
590
591 if ( ! is_null($limit))
592 {
593 $this->limit($limit, $offset);
594 }
595
596 $sql = $this->_compile_select();
597
598 $result = $this->query($sql);
599 $this->_reset_select();
600 return $result;
601 }
Derek Allard218e2bc2007-12-17 21:18:14 +0000602
603 // --------------------------------------------------------------------
604
605 /**
606 * getwhere() is an alias of get_where()
607 * this function is here for backwards compatibility, as
608 * getwhere() has been deprecated
609 */
610 function getwhere($table = '', $where = null, $limit = null, $offset = null)
611 {
612 return $this->get_where($table, $where, $limit, $offset);
613 }
Derek Allard09de1852007-02-14 01:35:56 +0000614
615 // --------------------------------------------------------------------
616
617 /**
618 * Insert
619 *
620 * Compiles an insert string and runs the query
621 *
622 * @access public
623 * @param string the table to retrieve the results from
624 * @param array an associative array of insert values
625 * @return object
626 */
627 function insert($table = '', $set = NULL)
628 {
629 if ( ! is_null($set))
630 {
631 $this->set($set);
632 }
633
634 if (count($this->ar_set) == 0)
635 {
636 if ($this->db_debug)
637 {
638 return $this->display_error('db_must_use_set');
639 }
640 return FALSE;
641 }
642
643 if ($table == '')
644 {
645 if ( ! isset($this->ar_from[0]))
646 {
647 if ($this->db_debug)
648 {
649 return $this->display_error('db_must_set_table');
650 }
651 return FALSE;
652 }
653
654 $table = $this->ar_from[0];
655 }
656
657 $sql = $this->_insert($this->dbprefix.$table, array_keys($this->ar_set), array_values($this->ar_set));
658
659 $this->_reset_write();
660 return $this->query($sql);
661 }
662
663 // --------------------------------------------------------------------
664
665 /**
666 * Update
667 *
668 * Compiles an update string and runs the query
669 *
670 * @access public
671 * @param string the table to retrieve the results from
672 * @param array an associative array of update values
673 * @param mixed the where clause
674 * @return object
675 */
676 function update($table = '', $set = NULL, $where = null)
677 {
678 if ( ! is_null($set))
679 {
680 $this->set($set);
681 }
682
683 if (count($this->ar_set) == 0)
684 {
685 if ($this->db_debug)
686 {
687 return $this->display_error('db_must_use_set');
688 }
689 return FALSE;
690 }
691
692 if ($table == '')
693 {
694 if ( ! isset($this->ar_from[0]))
695 {
696 if ($this->db_debug)
697 {
698 return $this->display_error('db_must_set_table');
699 }
700 return FALSE;
701 }
702
703 $table = $this->ar_from[0];
704 }
705
706 if ($where != null)
707 {
708 $this->where($where);
709 }
710
711 $sql = $this->_update($this->dbprefix.$table, $this->ar_set, $this->ar_where);
712
713 $this->_reset_write();
714 return $this->query($sql);
715 }
716
717 // --------------------------------------------------------------------
718
719 /**
720 * Delete
721 *
722 * Compiles a delete string and runs the query
723 *
724 * @access public
725 * @param string the table to retrieve the results from
726 * @param mixed the where clause
727 * @return object
728 */
729 function delete($table = '', $where = '')
730 {
731 if ($table == '')
732 {
733 if ( ! isset($this->ar_from[0]))
734 {
735 if ($this->db_debug)
736 {
737 return $this->display_error('db_must_set_table');
738 }
739 return FALSE;
740 }
741
742 $table = $this->ar_from[0];
743 }
744
745 if ($where != '')
746 {
747 $this->where($where);
748 }
749
750 if (count($this->ar_where) == 0)
751 {
752 if ($this->db_debug)
753 {
754 return $this->display_error('db_del_must_use_where');
755 }
756 return FALSE;
757 }
758
759 $sql = $this->_delete($this->dbprefix.$table, $this->ar_where);
760
761 $this->_reset_write();
762 return $this->query($sql);
763 }
764
765 // --------------------------------------------------------------------
766
767 /**
768 * Use Table - DEPRECATED
769 *
770 * @deprecated use $this->db->from instead
771 */
772 function use_table($table)
773 {
774 return $this->from($table);
775 return $this;
776 }
777
778 // --------------------------------------------------------------------
779
780 /**
Derek Allard09de1852007-02-14 01:35:56 +0000781 * Tests whether the string has an SQL operator
782 *
783 * @access private
784 * @param string
785 * @return bool
786 */
787 function _has_operator($str)
788 {
789 $str = trim($str);
790 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
791 {
792 return FALSE;
793 }
794
795 return TRUE;
796 }
797
798 // --------------------------------------------------------------------
799
800 /**
801 * Compile the SELECT statement
802 *
803 * Generates a query string based on which functions were used.
804 * Should not be called directly. The get() function calls it.
805 *
806 * @access private
807 * @return string
808 */
809 function _compile_select()
810 {
811 $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
812
813 $sql .= (count($this->ar_select) == 0) ? '*' : implode(', ', $this->ar_select);
814
815 if (count($this->ar_from) > 0)
816 {
817 $sql .= "\nFROM ";
818 $sql .= implode(', ', $this->ar_from);
819 }
820
821 if (count($this->ar_join) > 0)
822 {
823 $sql .= "\n";
824 $sql .= implode("\n", $this->ar_join);
825 }
826
827 if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
828 {
829 $sql .= "\nWHERE ";
830 }
831
832 $sql .= implode("\n", $this->ar_where);
833
834 if (count($this->ar_like) > 0)
835 {
836 if (count($this->ar_where) > 0)
837 {
838 $sql .= " AND ";
839 }
840
841 $sql .= implode("\n", $this->ar_like);
842 }
843
844 if (count($this->ar_groupby) > 0)
845 {
846 $sql .= "\nGROUP BY ";
847 $sql .= implode(', ', $this->ar_groupby);
848 }
849
850 if (count($this->ar_having) > 0)
851 {
852 $sql .= "\nHAVING ";
853 $sql .= implode("\n", $this->ar_having);
854 }
855
856 if (count($this->ar_orderby) > 0)
857 {
858 $sql .= "\nORDER BY ";
859 $sql .= implode(', ', $this->ar_orderby);
860
861 if ($this->ar_order !== FALSE)
862 {
863 $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
864 }
865 }
866
867 if (is_numeric($this->ar_limit))
868 {
869 $sql .= "\n";
870 $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
871 }
872
873 return $sql;
874 }
875
876 // --------------------------------------------------------------------
877
878 /**
879 * Object to Array
880 *
881 * Takes an object as input and converts the class variables to array key/vals
882 *
883 * @access public
884 * @param object
885 * @return array
886 */
887 function _object_to_array($object)
888 {
889 if ( ! is_object($object))
890 {
891 return $object;
892 }
893
894 $array = array();
895 foreach (get_object_vars($object) as $key => $val)
896 {
897 if ( ! is_object($val) AND ! is_array($val))
898 {
899 $array[$key] = $val;
900 }
901 }
902
903 return $array;
904 }
905
906 // --------------------------------------------------------------------
907
908 /**
909 * Resets the active record values. Called by the get() function
910 *
911 * @access private
912 * @return void
913 */
914 function _reset_select()
915 {
916 $this->ar_select = array();
917 $this->ar_distinct = FALSE;
918 $this->ar_from = array();
919 $this->ar_join = array();
920 $this->ar_where = array();
921 $this->ar_like = array();
922 $this->ar_groupby = array();
923 $this->ar_having = array();
924 $this->ar_limit = FALSE;
925 $this->ar_offset = FALSE;
926 $this->ar_order = FALSE;
927 $this->ar_orderby = array();
928 }
929
930 // --------------------------------------------------------------------
931
932 /**
933 * Resets the active record "write" values.
934 *
935 * Called by the insert() or update() functions
936 *
937 * @access private
938 * @return void
939 */
940 function _reset_write()
941 {
942 $this->ar_set = array();
943 $this->ar_from = array();
944 $this->ar_where = array();
945 }
946
947}
948
adminac94f382006-09-24 20:28:12 +0000949?>