blob: c757e6ae606d694d0ee482e0076a562559019c1a [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
9 * @copyright Copyright (c) 2008, EllisLab, Inc.
10 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://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 ExpressionEngine Dev Team
27 * @link http://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 var $ar_wherein = array();
45 var $ar_aliased_tables = array();
46 var $ar_store_array = array();
47
48 // Active Record Caching variables
49 var $ar_caching = FALSE;
50 var $ar_cache_exists = array();
51 var $ar_cache_select = array();
52 var $ar_cache_from = array();
53 var $ar_cache_join = array();
54 var $ar_cache_where = array();
55 var $ar_cache_like = array();
56 var $ar_cache_groupby = array();
57 var $ar_cache_having = array();
58 var $ar_cache_orderby = array();
59 var $ar_cache_set = array();
60
61
62 // --------------------------------------------------------------------
63
64 /**
65 * Select
66 *
67 * Generates the SELECT portion of the query
68 *
69 * @access public
70 * @param string
71 * @return object
72 */
73 function select($select = '*', $escape = NULL)
74 {
75 // Set the global value if this was sepecified
76 if (is_bool($escape))
77 {
78 $this->_protect_identifiers = $escape;
79 }
80
81 if (is_string($select))
82 {
83 $select = explode(',', $select);
84 }
85
86 foreach ($select as $val)
87 {
88 $val = trim($val);
89
90 if ($val != '')
91 {
92 $this->ar_select[] = $val;
93
94 if ($this->ar_caching === TRUE)
95 {
96 $this->ar_cache_select[] = $val;
97 $this->ar_cache_exists[] = 'select';
98 }
99 }
100 }
101 return $this;
102 }
103
104 // --------------------------------------------------------------------
105
106 /**
107 * Select Max
108 *
109 * Generates a SELECT MAX(field) portion of a query
110 *
111 * @access public
112 * @param string the field
113 * @param string an alias
114 * @return object
115 */
116 function select_max($select = '', $alias = '')
117 {
118 return $this->_max_min_avg_sum($select, $alias, 'MAX');
119 }
120
121 // --------------------------------------------------------------------
122
123 /**
124 * Select Min
125 *
126 * Generates a SELECT MIN(field) portion of a query
127 *
128 * @access public
129 * @param string the field
130 * @param string an alias
131 * @return object
132 */
133 function select_min($select = '', $alias = '')
134 {
135 return $this->_max_min_avg_sum($select, $alias, 'MIN');
136 }
137
138 // --------------------------------------------------------------------
139
140 /**
141 * Select Average
142 *
143 * Generates a SELECT AVG(field) portion of a query
144 *
145 * @access public
146 * @param string the field
147 * @param string an alias
148 * @return object
149 */
150 function select_avg($select = '', $alias = '')
151 {
152 return $this->_max_min_avg_sum($select, $alias, 'AVG');
153 }
154
155 // --------------------------------------------------------------------
156
157 /**
158 * Select Sum
159 *
160 * Generates a SELECT SUM(field) portion of a query
161 *
162 * @access public
163 * @param string the field
164 * @param string an alias
165 * @return object
166 */
167 function select_sum($select = '', $alias = '')
168 {
169 return $this->_max_min_avg_sum($select, $alias, 'SUM');
170 }
171
172 // --------------------------------------------------------------------
173
174 /**
175 * Processing Function for the four functions above:
176 *
177 * select_max()
178 * select_min()
179 * select_avg()
180 * select_sum()
181 *
182 * @access public
183 * @param string the field
184 * @param string an alias
185 * @return object
186 */
187 function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
188 {
189 if ( ! is_string($select) OR $select == '')
190 {
191 $this->display_error('db_invalid_query');
192 }
193
194 $type = strtoupper($type);
195
196 if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM')))
197 {
198 show_error('Invalid function type: '.$type);
199 }
200
201 if ($alias == '')
202 {
203 $alias = $this->_create_alias_from_table(trim($select));
204 }
205
206 $sql = $type.'('.$this->_protect_identifiers(trim($select)).') AS '.$alias;
207
208 $this->ar_select[] = $sql;
209
210 if ($this->ar_caching === TRUE)
211 {
212 $this->ar_cache_select[] = $sql;
213 $this->ar_cache_exists[] = 'select';
214 }
215
216 return $this;
217 }
218
219 // --------------------------------------------------------------------
220
221 /**
222 * Determines the alias name based on the table
223 *
224 * @access private
225 * @param string
226 * @return string
227 */
228 function _create_alias_from_table($item)
229 {
230 if (strpos($item, '.') !== FALSE)
231 {
232 return end(explode('.', $item));
233 }
234
235 return $item;
236 }
237
238 // --------------------------------------------------------------------
239
240 /**
241 * DISTINCT
242 *
243 * Sets a flag which tells the query string compiler to add DISTINCT
244 *
245 * @access public
246 * @param bool
247 * @return object
248 */
249 function distinct($val = TRUE)
250 {
251 $this->ar_distinct = (is_bool($val)) ? $val : TRUE;
252 return $this;
253 }
254
255 // --------------------------------------------------------------------
256
257 /**
258 * From
259 *
260 * Generates the FROM portion of the query
261 *
262 * @access public
263 * @param mixed can be a string or array
264 * @return object
265 */
266 function from($from)
267 {
268 foreach ((array)$from as $val)
269 {
270 if (strpos($val, ',') !== FALSE)
271 {
272 foreach (explode(',', $val) as $v)
273 {
274 $v = trim($v);
275 $this->_track_aliases($v);
276
277 $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
278
279 if ($this->ar_caching === TRUE)
280 {
281 $this->ar_cache_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
282 $this->ar_cache_exists[] = 'from';
283 }
284 }
285
286 }
287 else
288 {
289 $val = trim($val);
290
291 // Extract any aliases that might exist. We use this information
292 // in the _protect_identifiers to know whether to add a table prefix
293 $this->_track_aliases($val);
294
295 $this->ar_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
296
297 if ($this->ar_caching === TRUE)
298 {
299 $this->ar_cache_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
300 $this->ar_cache_exists[] = 'from';
301 }
302 }
303 }
304
305 return $this;
306 }
307
308 // --------------------------------------------------------------------
309
310 /**
311 * Join
312 *
313 * Generates the JOIN portion of the query
314 *
315 * @access public
316 * @param string
317 * @param string the join condition
318 * @param string the type of join
319 * @return object
320 */
321 function join($table, $cond, $type = '')
322 {
323 if ($type != '')
324 {
325 $type = strtoupper(trim($type));
326
327 if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
328 {
329 $type = '';
330 }
331 else
332 {
333 $type .= ' ';
334 }
335 }
336
337 // Extract any aliases that might exist. We use this information
338 // in the _protect_identifiers to know whether to add a table prefix
339 $this->_track_aliases($table);
340
341 // Strip apart the condition and protect the identifiers
342 if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
343 {
344 $match[1] = $this->_protect_identifiers($match[1]);
345 $match[3] = $this->_protect_identifiers($match[3]);
346
347 $cond = $match[1].$match[2].$match[3];
348 }
349
350 // Assemble the JOIN statement
351 $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
352
353 $this->ar_join[] = $join;
354 if ($this->ar_caching === TRUE)
355 {
356 $this->ar_cache_join[] = $join;
357 $this->ar_cache_exists[] = 'join';
358 }
359
360 return $this;
361 }
362
363 // --------------------------------------------------------------------
364
365 /**
366 * Where
367 *
368 * Generates the WHERE portion of the query. Separates
369 * multiple calls with AND
370 *
371 * @access public
372 * @param mixed
373 * @param mixed
374 * @return object
375 */
376 function where($key, $value = NULL, $escape = TRUE)
377 {
378 return $this->_where($key, $value, 'AND ', $escape);
379 }
380
381 // --------------------------------------------------------------------
382
383 /**
384 * OR Where
385 *
386 * Generates the WHERE portion of the query. Separates
387 * multiple calls with OR
388 *
389 * @access public
390 * @param mixed
391 * @param mixed
392 * @return object
393 */
394 function or_where($key, $value = NULL, $escape = TRUE)
395 {
396 return $this->_where($key, $value, 'OR ', $escape);
397 }
398
399 // --------------------------------------------------------------------
400
401 /**
402 * orwhere() is an alias of or_where()
403 * this function is here for backwards compatibility, as
404 * orwhere() has been deprecated
405 */
406 function orwhere($key, $value = NULL, $escape = TRUE)
407 {
408 return $this->or_where($key, $value, $escape);
409 }
410
411 // --------------------------------------------------------------------
412
413 /**
414 * Where
415 *
416 * Called by where() or orwhere()
417 *
418 * @access private
419 * @param mixed
420 * @param mixed
421 * @param string
422 * @return object
423 */
424 function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
425 {
426 if ( ! is_array($key))
427 {
428 $key = array($key => $value);
429 }
430
431 // If the escape value was not set will will base it on the global setting
432 if ( ! is_bool($escape))
433 {
434 $escape = $this->_protect_identifiers;
435 }
436
437 foreach ($key as $k => $v)
438 {
439 $prefix = (count($this->ar_where) == 0 AND count($this->ar_cache_where) == 0) ? '' : $type;
440
441 if (is_null($v) && ! $this->_has_operator($k))
442 {
443 // value appears not to have been set, assign the test to IS NULL
444 $k .= ' IS NULL';
445 }
446
447 if ( ! is_null($v))
448 {
449 if ($escape === TRUE)
450 {
451 $k = $this->_protect_identifiers($k, FALSE, $escape);
452
453 $v = ' '.$this->escape($v);
454 }
455
456 if ( ! $this->_has_operator($k))
457 {
458 $k .= ' =';
459 }
460 }
461 else
462 {
463 $k = $this->_protect_identifiers($k, FALSE, $escape);
464 }
465
466 $this->ar_where[] = $prefix.$k.$v;
467
468 if ($this->ar_caching === TRUE)
469 {
470 $this->ar_cache_where[] = $prefix.$k.$v;
471 $this->ar_cache_exists[] = 'where';
472 }
473
474 }
475
476 return $this;
477 }
478
479 // --------------------------------------------------------------------
480
481 /**
482 * Where_in
483 *
484 * Generates a WHERE field IN ('item', 'item') SQL query joined with
485 * AND if appropriate
486 *
487 * @access public
488 * @param string The field to search
489 * @param array The values searched on
490 * @return object
491 */
492 function where_in($key = NULL, $values = NULL)
493 {
494 return $this->_where_in($key, $values);
495 }
496
497 // --------------------------------------------------------------------
498
499 /**
500 * Where_in_or
501 *
502 * Generates a WHERE field IN ('item', 'item') SQL query joined with
503 * OR if appropriate
504 *
505 * @access public
506 * @param string The field to search
507 * @param array The values searched on
508 * @return object
509 */
510 function or_where_in($key = NULL, $values = NULL)
511 {
512 return $this->_where_in($key, $values, FALSE, 'OR ');
513 }
514
515 // --------------------------------------------------------------------
516
517 /**
518 * Where_not_in
519 *
520 * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
521 * with AND if appropriate
522 *
523 * @access public
524 * @param string The field to search
525 * @param array The values searched on
526 * @return object
527 */
528 function where_not_in($key = NULL, $values = NULL)
529 {
530 return $this->_where_in($key, $values, TRUE);
531 }
532
533 // --------------------------------------------------------------------
534
535 /**
536 * Where_not_in_or
537 *
538 * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
539 * with OR if appropriate
540 *
541 * @access public
542 * @param string The field to search
543 * @param array The values searched on
544 * @return object
545 */
546 function or_where_not_in($key = NULL, $values = NULL)
547 {
548 return $this->_where_in($key, $values, TRUE, 'OR ');
549 }
550
551 // --------------------------------------------------------------------
552
553 /**
554 * Where_in
555 *
556 * Called by where_in, where_in_or, where_not_in, where_not_in_or
557 *
558 * @access public
559 * @param string The field to search
560 * @param array The values searched on
561 * @param boolean If the statement would be IN or NOT IN
562 * @param string
563 * @return object
564 */
565 function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
566 {
567 if ($key === NULL OR $values === NULL)
568 {
569 return;
570 }
571
572 if ( ! is_array($values))
573 {
574 $values = array($values);
575 }
576
577 $not = ($not) ? ' NOT' : '';
578
579 foreach ($values as $value)
580 {
581 $this->ar_wherein[] = $this->escape($value);
582 }
583
584 $prefix = (count($this->ar_where) == 0) ? '' : $type;
585
586 $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") ";
587
588 $this->ar_where[] = $where_in;
589 if ($this->ar_caching === TRUE)
590 {
591 $this->ar_cache_where[] = $where_in;
592 $this->ar_cache_exists[] = 'where';
593 }
594
595 // reset the array for multiple calls
596 $this->ar_wherein = array();
597 return $this;
598 }
599
600 // --------------------------------------------------------------------
601
602 /**
603 * Like
604 *
605 * Generates a %LIKE% portion of the query. Separates
606 * multiple calls with AND
607 *
608 * @access public
609 * @param mixed
610 * @param mixed
611 * @return object
612 */
613 function like($field, $match = '', $side = 'both')
614 {
615 return $this->_like($field, $match, 'AND ', $side);
616 }
617
618 // --------------------------------------------------------------------
619
620 /**
621 * Not Like
622 *
623 * Generates a NOT LIKE portion of the query. Separates
624 * multiple calls with AND
625 *
626 * @access public
627 * @param mixed
628 * @param mixed
629 * @return object
630 */
631 function not_like($field, $match = '', $side = 'both')
632 {
633 return $this->_like($field, $match, 'AND ', $side, 'NOT');
634 }
635
636 // --------------------------------------------------------------------
637
638 /**
639 * OR Like
640 *
641 * Generates a %LIKE% portion of the query. Separates
642 * multiple calls with OR
643 *
644 * @access public
645 * @param mixed
646 * @param mixed
647 * @return object
648 */
649 function or_like($field, $match = '', $side = 'both')
650 {
651 return $this->_like($field, $match, 'OR ', $side);
652 }
653
654 // --------------------------------------------------------------------
655
656 /**
657 * OR Not Like
658 *
659 * Generates a NOT LIKE portion of the query. Separates
660 * multiple calls with OR
661 *
662 * @access public
663 * @param mixed
664 * @param mixed
665 * @return object
666 */
667 function or_not_like($field, $match = '', $side = 'both')
668 {
669 return $this->_like($field, $match, 'OR ', $side, 'NOT');
670 }
671
672 // --------------------------------------------------------------------
673
674 /**
675 * orlike() is an alias of or_like()
676 * this function is here for backwards compatibility, as
677 * orlike() has been deprecated
678 */
679 function orlike($field, $match = '', $side = 'both')
680 {
681 return $this->or_like($field, $match, $side);
682 }
683
684 // --------------------------------------------------------------------
685
686 /**
687 * Like
688 *
689 * Called by like() or orlike()
690 *
691 * @access private
692 * @param mixed
693 * @param mixed
694 * @param string
695 * @return object
696 */
697 function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
698 {
699 if ( ! is_array($field))
700 {
701 $field = array($field => $match);
702 }
703
704 foreach ($field as $k => $v)
705 {
706 $k = $this->_protect_identifiers($k);
707
708 $prefix = (count($this->ar_like) == 0) ? '' : $type;
709
710 $v = $this->escape_str($v);
711
712 if ($side == 'before')
713 {
714 $like_statement = $prefix." $k $not LIKE '%{$v}'";
715 }
716 elseif ($side == 'after')
717 {
718 $like_statement = $prefix." $k $not LIKE '{$v}%'";
719 }
720 else
721 {
722 $like_statement = $prefix." $k $not LIKE '%{$v}%'";
723 }
724
725 $this->ar_like[] = $like_statement;
726 if ($this->ar_caching === TRUE)
727 {
728 $this->ar_cache_like[] = $like_statement;
729 $this->ar_cache_exists[] = 'like';
730 }
731
732 }
733 return $this;
734 }
735
736 // --------------------------------------------------------------------
737
738 /**
739 * GROUP BY
740 *
741 * @access public
742 * @param string
743 * @return object
744 */
745 function group_by($by)
746 {
747 if (is_string($by))
748 {
749 $by = explode(',', $by);
750 }
751
752 foreach ($by as $val)
753 {
754 $val = trim($val);
755
756 if ($val != '')
757 {
758 $this->ar_groupby[] = $this->_protect_identifiers($val);
759
760 if ($this->ar_caching === TRUE)
761 {
762 $this->ar_cache_groupby[] = $this->_protect_identifiers($val);
763 $this->ar_cache_exists[] = 'groupby';
764 }
765 }
766 }
767 return $this;
768 }
769
770 // --------------------------------------------------------------------
771
772 /**
773 * groupby() is an alias of group_by()
774 * this function is here for backwards compatibility, as
775 * groupby() has been deprecated
776 */
777 function groupby($by)
778 {
779 return $this->group_by($by);
780 }
781
782 // --------------------------------------------------------------------
783
784 /**
785 * Sets the HAVING value
786 *
787 * Separates multiple calls with AND
788 *
789 * @access public
790 * @param string
791 * @param string
792 * @return object
793 */
794 function having($key, $value = '', $escape = TRUE)
795 {
796 return $this->_having($key, $value, 'AND ', $escape);
797 }
798
799 // --------------------------------------------------------------------
800
801 /**
802 * orhaving() is an alias of or_having()
803 * this function is here for backwards compatibility, as
804 * orhaving() has been deprecated
805 */
806
807 function orhaving($key, $value = '', $escape = TRUE)
808 {
809 return $this->or_having($key, $value, $escape);
810 }
811 // --------------------------------------------------------------------
812
813 /**
814 * Sets the OR HAVING value
815 *
816 * Separates multiple calls with OR
817 *
818 * @access public
819 * @param string
820 * @param string
821 * @return object
822 */
823 function or_having($key, $value = '', $escape = TRUE)
824 {
825 return $this->_having($key, $value, 'OR ', $escape);
826 }
827
828 // --------------------------------------------------------------------
829
830 /**
831 * Sets the HAVING values
832 *
833 * Called by having() or or_having()
834 *
835 * @access private
836 * @param string
837 * @param string
838 * @return object
839 */
840 function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
841 {
842 if ( ! is_array($key))
843 {
844 $key = array($key => $value);
845 }
846
847 foreach ($key as $k => $v)
848 {
849 $prefix = (count($this->ar_having) == 0) ? '' : $type;
850
851 if ($escape === TRUE)
852 {
853 $k = $this->_protect_identifiers($k);
854 }
855
856 if ( ! $this->_has_operator($k))
857 {
858 $k .= ' = ';
859 }
860
861 if ($v != '')
862 {
863 $v = ' '.$this->escape_str($v);
864 }
865
866 $this->ar_having[] = $prefix.$k.$v;
867 if ($this->ar_caching === TRUE)
868 {
869 $this->ar_cache_having[] = $prefix.$k.$v;
870 $this->ar_cache_exists[] = 'having';
871 }
872 }
873
874 return $this;
875 }
876
877 // --------------------------------------------------------------------
878
879 /**
880 * Sets the ORDER BY value
881 *
882 * @access public
883 * @param string
884 * @param string direction: asc or desc
885 * @return object
886 */
887 function order_by($orderby, $direction = '')
888 {
889 if (strtolower($direction) == 'random')
890 {
891 $orderby = ''; // Random results want or don't need a field name
892 $direction = $this->_random_keyword;
893 }
894 elseif (trim($direction) != '')
895 {
896 $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
897 }
898
899
900 if (strpos($orderby, ',') !== FALSE)
901 {
902 $temp = array();
903 foreach (explode(',', $orderby) as $part)
904 {
905 $part = trim($part);
906 if ( ! in_array($part, $this->ar_aliased_tables))
907 {
908 $part = $this->_protect_identifiers(trim($part));
909 }
910
911 $temp[] = $part;
912 }
913
914 $orderby = implode(', ', $temp);
915 }
Derek Allarde37ab382009-02-03 16:13:57 +0000916 else if ($direction != $this->_random_keyword)
Derek Allard2067d1a2008-11-13 22:59:24 +0000917 {
918 $orderby = $this->_protect_identifiers($orderby);
919 }
920
921 $orderby_statement = $orderby.$direction;
922
923 $this->ar_orderby[] = $orderby_statement;
924 if ($this->ar_caching === TRUE)
925 {
926 $this->ar_cache_orderby[] = $orderby_statement;
927 $this->ar_cache_exists[] = 'orderby';
928 }
929
930 return $this;
931 }
932
933 // --------------------------------------------------------------------
934
935 /**
936 * orderby() is an alias of order_by()
937 * this function is here for backwards compatibility, as
938 * orderby() has been deprecated
939 */
940 function orderby($orderby, $direction = '')
941 {
942 return $this->order_by($orderby, $direction);
943 }
944
945 // --------------------------------------------------------------------
946
947 /**
948 * Sets the LIMIT value
949 *
950 * @access public
951 * @param integer the limit value
952 * @param integer the offset value
953 * @return object
954 */
955 function limit($value, $offset = '')
956 {
957 $this->ar_limit = $value;
958
959 if ($offset != '')
960 {
961 $this->ar_offset = $offset;
962 }
963
964 return $this;
965 }
966
967 // --------------------------------------------------------------------
968
969 /**
970 * Sets the OFFSET value
971 *
972 * @access public
973 * @param integer the offset value
974 * @return object
975 */
976 function offset($offset)
977 {
978 $this->ar_offset = $offset;
979 return $this;
980 }
981
982 // --------------------------------------------------------------------
983
984 /**
985 * The "set" function. Allows key/value pairs to be set for inserting or updating
986 *
987 * @access public
988 * @param mixed
989 * @param string
990 * @param boolean
991 * @return object
992 */
993 function set($key, $value = '', $escape = TRUE)
994 {
995 $key = $this->_object_to_array($key);
996
997 if ( ! is_array($key))
998 {
999 $key = array($key => $value);
1000 }
1001
1002 foreach ($key as $k => $v)
1003 {
1004 if ($escape === FALSE)
1005 {
1006 $this->ar_set[$this->_protect_identifiers($k)] = $v;
1007 }
1008 else
1009 {
1010 $this->ar_set[$this->_protect_identifiers($k)] = $this->escape($v);
1011 }
1012 }
1013
1014 return $this;
1015 }
1016
1017 // --------------------------------------------------------------------
1018
1019 /**
1020 * Get
1021 *
1022 * Compiles the select statement based on the other functions called
1023 * and runs the query
1024 *
1025 * @access public
1026 * @param string the table
1027 * @param string the limit clause
1028 * @param string the offset clause
1029 * @return object
1030 */
1031 function get($table = '', $limit = null, $offset = null)
1032 {
1033 if ($table != '')
1034 {
1035 $this->_track_aliases($table);
1036 $this->from($table);
1037 }
1038
1039 if ( ! is_null($limit))
1040 {
1041 $this->limit($limit, $offset);
1042 }
1043
1044 $sql = $this->_compile_select();
1045
1046 $result = $this->query($sql);
1047 $this->_reset_select();
1048 return $result;
1049 }
1050
1051 /**
1052 * "Count All Results" query
1053 *
1054 * Generates a platform-specific query string that counts all records
1055 * returned by an Active Record query.
1056 *
1057 * @access public
1058 * @param string
1059 * @return string
1060 */
1061 function count_all_results($table = '')
1062 {
1063 if ($table != '')
1064 {
1065 $this->_track_aliases($table);
1066 $this->from($table);
1067 }
1068
1069 $sql = $this->_compile_select($this->_count_string . $this->_protect_identifiers('numrows'));
1070
1071 $query = $this->query($sql);
1072 $this->_reset_select();
1073
1074 if ($query->num_rows() == 0)
1075 {
1076 return '0';
1077 }
1078
1079 $row = $query->row();
1080 return $row->numrows;
1081 }
1082
1083 // --------------------------------------------------------------------
1084
1085 /**
1086 * Get_Where
1087 *
1088 * Allows the where clause, limit and offset to be added directly
1089 *
1090 * @access public
1091 * @param string the where clause
1092 * @param string the limit clause
1093 * @param string the offset clause
1094 * @return object
1095 */
1096 function get_where($table = '', $where = null, $limit = null, $offset = null)
1097 {
1098 if ($table != '')
1099 {
1100 $this->from($table);
1101 }
1102
1103 if ( ! is_null($where))
1104 {
1105 $this->where($where);
1106 }
1107
1108 if ( ! is_null($limit))
1109 {
1110 $this->limit($limit, $offset);
1111 }
1112
1113 $sql = $this->_compile_select();
1114
1115 $result = $this->query($sql);
1116 $this->_reset_select();
1117 return $result;
1118 }
1119
1120 // --------------------------------------------------------------------
1121
1122 /**
1123 * getwhere() is an alias of get_where()
1124 * this function is here for backwards compatibility, as
1125 * getwhere() has been deprecated
1126 */
1127 function getwhere($table = '', $where = null, $limit = null, $offset = null)
1128 {
1129 return $this->get_where($table, $where, $limit, $offset);
1130 }
1131
1132 // --------------------------------------------------------------------
1133
1134 /**
1135 * Insert
1136 *
1137 * Compiles an insert string and runs the query
1138 *
1139 * @access public
1140 * @param string the table to retrieve the results from
1141 * @param array an associative array of insert values
1142 * @return object
1143 */
1144 function insert($table = '', $set = NULL)
1145 {
1146 if ( ! is_null($set))
1147 {
1148 $this->set($set);
1149 }
1150
1151 if (count($this->ar_set) == 0)
1152 {
1153 if ($this->db_debug)
1154 {
1155 return $this->display_error('db_must_use_set');
1156 }
1157 return FALSE;
1158 }
1159
1160 if ($table == '')
1161 {
1162 if ( ! isset($this->ar_from[0]))
1163 {
1164 if ($this->db_debug)
1165 {
1166 return $this->display_error('db_must_set_table');
1167 }
1168 return FALSE;
1169 }
1170
1171 $table = $this->ar_from[0];
1172 }
1173
1174 $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set));
1175
1176 $this->_reset_write();
1177 return $this->query($sql);
1178 }
1179
1180 // --------------------------------------------------------------------
1181
1182 /**
1183 * Update
1184 *
1185 * Compiles an update string and runs the query
1186 *
1187 * @access public
1188 * @param string the table to retrieve the results from
1189 * @param array an associative array of update values
1190 * @param mixed the where clause
1191 * @return object
1192 */
1193 function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
1194 {
1195 // Combine any cached components with the current statements
1196 $this->_merge_cache();
1197
1198 if ( ! is_null($set))
1199 {
1200 $this->set($set);
1201 }
1202
1203 if (count($this->ar_set) == 0)
1204 {
1205 if ($this->db_debug)
1206 {
1207 return $this->display_error('db_must_use_set');
1208 }
1209 return FALSE;
1210 }
1211
1212 if ($table == '')
1213 {
1214 if ( ! isset($this->ar_from[0]))
1215 {
1216 if ($this->db_debug)
1217 {
1218 return $this->display_error('db_must_set_table');
1219 }
1220 return FALSE;
1221 }
1222
1223 $table = $this->ar_from[0];
1224 }
1225
1226 if ($where != NULL)
1227 {
1228 $this->where($where);
1229 }
1230
1231 if ($limit != NULL)
1232 {
1233 $this->limit($limit);
1234 }
1235
1236 $sql = $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit);
1237
1238 $this->_reset_write();
1239 return $this->query($sql);
1240 }
1241
1242 // --------------------------------------------------------------------
1243
1244 /**
1245 * Empty Table
1246 *
1247 * Compiles a delete string and runs "DELETE FROM table"
1248 *
1249 * @access public
1250 * @param string the table to empty
1251 * @return object
1252 */
1253 function empty_table($table = '')
1254 {
1255 if ($table == '')
1256 {
1257 if ( ! isset($this->ar_from[0]))
1258 {
1259 if ($this->db_debug)
1260 {
1261 return $this->display_error('db_must_set_table');
1262 }
1263 return FALSE;
1264 }
1265
1266 $table = $this->ar_from[0];
1267 }
1268 else
1269 {
1270 $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1271 }
1272
1273 $sql = $this->_delete($table);
1274
1275 $this->_reset_write();
1276
1277 return $this->query($sql);
1278 }
1279
1280 // --------------------------------------------------------------------
1281
1282 /**
1283 * Truncate
1284 *
1285 * Compiles a truncate string and runs the query
1286 * If the database does not support the truncate() command
1287 * This function maps to "DELETE FROM table"
1288 *
1289 * @access public
1290 * @param string the table to truncate
1291 * @return object
1292 */
1293 function truncate($table = '')
1294 {
1295 if ($table == '')
1296 {
1297 if ( ! isset($this->ar_from[0]))
1298 {
1299 if ($this->db_debug)
1300 {
1301 return $this->display_error('db_must_set_table');
1302 }
1303 return FALSE;
1304 }
1305
1306 $table = $this->ar_from[0];
1307 }
1308 else
1309 {
1310 $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1311 }
1312
1313 $sql = $this->_truncate($table);
1314
1315 $this->_reset_write();
1316
1317 return $this->query($sql);
1318 }
1319
1320 // --------------------------------------------------------------------
1321
1322 /**
1323 * Delete
1324 *
1325 * Compiles a delete string and runs the query
1326 *
1327 * @access public
1328 * @param mixed the table(s) to delete from. String or array
1329 * @param mixed the where clause
1330 * @param mixed the limit clause
1331 * @param boolean
1332 * @return object
1333 */
1334 function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
1335 {
1336 // Combine any cached components with the current statements
1337 $this->_merge_cache();
1338
1339 if ($table == '')
1340 {
1341 if ( ! isset($this->ar_from[0]))
1342 {
1343 if ($this->db_debug)
1344 {
1345 return $this->display_error('db_must_set_table');
1346 }
1347 return FALSE;
1348 }
1349
1350 $table = $this->ar_from[0];
1351 }
1352 elseif (is_array($table))
1353 {
1354 foreach($table as $single_table)
1355 {
1356 $this->delete($single_table, $where, $limit, FALSE);
1357 }
1358
1359 $this->_reset_write();
1360 return;
1361 }
1362 else
1363 {
1364 $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
1365 }
1366
1367 if ($where != '')
1368 {
1369 $this->where($where);
1370 }
1371
1372 if ($limit != NULL)
1373 {
1374 $this->limit($limit);
1375 }
1376
Derek Allardef22efd2008-11-20 15:25:45 +00001377 if (count($this->ar_where) == 0 && count($this->ar_wherein) == 0 && count($this->ar_like))
Derek Allard2067d1a2008-11-13 22:59:24 +00001378 {
1379 if ($this->db_debug)
1380 {
1381 return $this->display_error('db_del_must_use_where');
1382 }
1383
1384 return FALSE;
1385 }
1386
1387 $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit);
1388
1389 if ($reset_data)
1390 {
1391 $this->_reset_write();
1392 }
1393
1394 return $this->query($sql);
1395 }
1396
1397 // --------------------------------------------------------------------
1398
1399 /**
1400 * DB Prefix
1401 *
1402 * Prepends a database prefix if one exists in configuration
1403 *
1404 * @access public
1405 * @param string the table
1406 * @return string
1407 */
1408 function dbprefix($table = '')
1409 {
1410 if ($table == '')
1411 {
1412 $this->display_error('db_table_name_required');
1413 }
1414
1415 return $this->dbprefix.$table;
1416 }
1417
1418 // --------------------------------------------------------------------
1419
1420 /**
1421 * Track Aliases
1422 *
1423 * Used to track SQL statements written with aliased tables.
1424 *
1425 * @access private
1426 * @param string The table to inspect
1427 * @return string
1428 */
1429 function _track_aliases($table)
1430 {
1431 if (is_array($table))
1432 {
1433 foreach ($table as $t)
1434 {
1435 $this->_track_aliases($t);
1436 }
1437 return;
1438 }
1439
1440 // Does the string contain a comma? If so, we need to separate
1441 // the string into discreet statements
1442 if (strpos($table, ',') !== FALSE)
1443 {
1444 return $this->_track_aliases(explode(',', $table));
1445 }
1446
1447 // if a table alias is used we can recognize it by a space
1448 if (strpos($table, " ") !== FALSE)
1449 {
1450 // if the alias is written with the AS keyword, remove it
1451 $table = preg_replace('/ AS /i', ' ', $table);
1452
1453 // Grab the alias
1454 $table = trim(strrchr($table, " "));
1455
1456 // Store the alias, if it doesn't already exist
1457 if ( ! in_array($table, $this->ar_aliased_tables))
1458 {
1459 $this->ar_aliased_tables[] = $table;
1460 }
1461 }
1462 }
1463
1464 // --------------------------------------------------------------------
1465
1466 /**
1467 * Compile the SELECT statement
1468 *
1469 * Generates a query string based on which functions were used.
1470 * Should not be called directly. The get() function calls it.
1471 *
1472 * @access private
1473 * @return string
1474 */
1475 function _compile_select($select_override = FALSE)
1476 {
1477 // Combine any cached components with the current statements
1478 $this->_merge_cache();
1479
1480 // ----------------------------------------------------------------
1481
1482 // Write the "select" portion of the query
1483
1484 if ($select_override !== FALSE)
1485 {
1486 $sql = $select_override;
1487 }
1488 else
1489 {
1490 $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
1491
1492 if (count($this->ar_select) == 0)
1493 {
1494 $sql .= '*';
1495 }
1496 else
1497 {
1498 // Cycle through the "select" portion of the query and prep each column name.
1499 // The reason we protect identifiers here rather then in the select() function
1500 // is because until the user calls the from() function we don't know if there are aliases
1501 foreach ($this->ar_select as $key => $val)
1502 {
1503 $this->ar_select[$key] = $this->_protect_identifiers($val);
1504 }
1505
1506 $sql .= implode(', ', $this->ar_select);
1507 }
1508 }
1509
1510 // ----------------------------------------------------------------
1511
1512 // Write the "FROM" portion of the query
1513
1514 if (count($this->ar_from) > 0)
1515 {
1516 $sql .= "\nFROM ";
1517
1518 $sql .= $this->_from_tables($this->ar_from);
1519 }
1520
1521 // ----------------------------------------------------------------
1522
1523 // Write the "JOIN" portion of the query
1524
1525 if (count($this->ar_join) > 0)
1526 {
1527 $sql .= "\n";
1528
1529 $sql .= implode("\n", $this->ar_join);
1530 }
1531
1532 // ----------------------------------------------------------------
1533
1534 // Write the "WHERE" portion of the query
1535
1536 if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
1537 {
1538 $sql .= "\n";
1539
1540 $sql .= "WHERE ";
1541 }
1542
1543 $sql .= implode("\n", $this->ar_where);
1544
1545 // ----------------------------------------------------------------
1546
1547 // Write the "LIKE" portion of the query
1548
1549 if (count($this->ar_like) > 0)
1550 {
1551 if (count($this->ar_where) > 0)
1552 {
1553 $sql .= "\nAND ";
1554 }
1555
1556 $sql .= implode("\n", $this->ar_like);
1557 }
1558
1559 // ----------------------------------------------------------------
1560
1561 // Write the "GROUP BY" portion of the query
1562
1563 if (count($this->ar_groupby) > 0)
1564 {
1565 $sql .= "\nGROUP BY ";
1566
1567 $sql .= implode(', ', $this->ar_groupby);
1568 }
1569
1570 // ----------------------------------------------------------------
1571
1572 // Write the "HAVING" portion of the query
1573
1574 if (count($this->ar_having) > 0)
1575 {
1576 $sql .= "\nHAVING ";
1577 $sql .= implode("\n", $this->ar_having);
1578 }
1579
1580 // ----------------------------------------------------------------
1581
1582 // Write the "ORDER BY" portion of the query
1583
1584 if (count($this->ar_orderby) > 0)
1585 {
1586 $sql .= "\nORDER BY ";
1587 $sql .= implode(', ', $this->ar_orderby);
1588
1589 if ($this->ar_order !== FALSE)
1590 {
1591 $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
1592 }
1593 }
1594
1595 // ----------------------------------------------------------------
1596
1597 // Write the "LIMIT" portion of the query
1598
1599 if (is_numeric($this->ar_limit))
1600 {
1601 $sql .= "\n";
1602 $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
1603 }
1604
1605 return $sql;
1606 }
1607
1608 // --------------------------------------------------------------------
1609
1610 /**
1611 * Object to Array
1612 *
1613 * Takes an object as input and converts the class variables to array key/vals
1614 *
1615 * @access public
1616 * @param object
1617 * @return array
1618 */
1619 function _object_to_array($object)
1620 {
1621 if ( ! is_object($object))
1622 {
1623 return $object;
1624 }
1625
1626 $array = array();
1627 foreach (get_object_vars($object) as $key => $val)
1628 {
1629 // There are some built in keys we need to ignore for this conversion
1630 if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name' && $key != '_ci_scaffolding' && $key != '_ci_scaff_table')
1631 {
1632 $array[$key] = $val;
1633 }
1634 }
1635
1636 return $array;
1637 }
1638
1639 // --------------------------------------------------------------------
1640
1641 /**
1642 * Start Cache
1643 *
1644 * Starts AR caching
1645 *
1646 * @access public
1647 * @return void
1648 */
1649 function start_cache()
1650 {
1651 $this->ar_caching = TRUE;
1652 }
1653
1654 // --------------------------------------------------------------------
1655
1656 /**
1657 * Stop Cache
1658 *
1659 * Stops AR caching
1660 *
1661 * @access public
1662 * @return void
1663 */
1664 function stop_cache()
1665 {
1666 $this->ar_caching = FALSE;
1667 }
1668
1669 // --------------------------------------------------------------------
1670
1671 /**
1672 * Flush Cache
1673 *
1674 * Empties the AR cache
1675 *
1676 * @access public
1677 * @return void
1678 */
1679 function flush_cache()
1680 {
1681 $this->_reset_run(
1682 array(
1683 'ar_cache_select' => array(),
1684 'ar_cache_from' => array(),
1685 'ar_cache_join' => array(),
1686 'ar_cache_where' => array(),
1687 'ar_cache_like' => array(),
1688 'ar_cache_groupby' => array(),
1689 'ar_cache_having' => array(),
1690 'ar_cache_orderby' => array(),
1691 'ar_cache_set' => array(),
1692 'ar_cache_exists' => array()
1693 )
1694 );
1695 }
1696
1697 // --------------------------------------------------------------------
1698
1699 /**
1700 * Merge Cache
1701 *
1702 * When called, this function merges any cached AR arrays with
1703 * locally called ones.
1704 *
1705 * @access private
1706 * @return void
1707 */
1708 function _merge_cache()
1709 {
1710 if (count($this->ar_cache_exists) == 0)
1711 {
1712 return;
1713 }
1714
1715 foreach ($this->ar_cache_exists as $val)
1716 {
1717 $ar_variable = 'ar_'.$val;
1718 $ar_cache_var = 'ar_cache_'.$val;
1719
1720 if (count($this->$ar_cache_var) == 0)
1721 {
1722 continue;
1723 }
1724
1725 $this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable));
1726 }
1727
1728 // If we are "protecting identifiers" we need to examine the "from"
1729 // portion of the query to determine if there are any aliases
1730 if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0)
1731 {
1732 $this->_track_aliases($this->ar_from);
1733 }
1734 }
1735
1736 // --------------------------------------------------------------------
1737
1738 /**
1739 * Resets the active record values. Called by the get() function
1740 *
1741 * @access private
1742 * @param array An array of fields to reset
1743 * @return void
1744 */
1745 function _reset_run($ar_reset_items)
1746 {
1747 foreach ($ar_reset_items as $item => $default_value)
1748 {
1749 if ( ! in_array($item, $this->ar_store_array))
1750 {
1751 $this->$item = $default_value;
1752 }
1753 }
1754 }
1755
1756 // --------------------------------------------------------------------
1757
1758 /**
1759 * Resets the active record values. Called by the get() function
1760 *
1761 * @access private
1762 * @return void
1763 */
1764 function _reset_select()
1765 {
1766 $ar_reset_items = array(
1767 'ar_select' => array(),
1768 'ar_from' => array(),
1769 'ar_join' => array(),
1770 'ar_where' => array(),
1771 'ar_like' => array(),
1772 'ar_groupby' => array(),
1773 'ar_having' => array(),
1774 'ar_orderby' => array(),
1775 'ar_wherein' => array(),
1776 'ar_aliased_tables' => array(),
1777 'ar_distinct' => FALSE,
1778 'ar_limit' => FALSE,
1779 'ar_offset' => FALSE,
1780 'ar_order' => FALSE,
1781 );
1782
1783 $this->_reset_run($ar_reset_items);
1784 }
1785
1786 // --------------------------------------------------------------------
1787
1788 /**
1789 * Resets the active record "write" values.
1790 *
1791 * Called by the insert() update() and delete() functions
1792 *
1793 * @access private
1794 * @return void
1795 */
1796 function _reset_write()
1797 {
1798 $ar_reset_items = array(
1799 'ar_set' => array(),
1800 'ar_from' => array(),
1801 'ar_where' => array(),
1802 'ar_like' => array(),
1803 'ar_orderby' => array(),
1804 'ar_limit' => FALSE,
1805 'ar_order' => FALSE
1806 );
1807
1808 $this->_reset_run($ar_reset_items);
1809 }
1810
1811}
1812
1813/* End of file DB_active_rec.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +00001814/* Location: ./system/database/DB_active_rec.php */