blob: 82d5b63b7566bdd40d9bc5d314f714ee9298999a [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 Allard09de1852007-02-14 01:35:56 +000010 * @license http://www.codeignitor.com/user_guide/license.html
11 * @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 */
188 function orwhere($key, $value = NULL)
189 {
190 return $this->_where($key, $value, 'OR ');
191 }
192
193 // --------------------------------------------------------------------
194
195 /**
196 * Where
197 *
198 * Called by where() or orwhere()
199 *
200 * @access private
201 * @param mixed
202 * @param mixed
203 * @param string
204 * @return object
205 */
206 function _where($key, $value = NULL, $type = 'AND ')
207 {
208 if ( ! is_array($key))
209 {
210 $key = array($key => $value);
211 }
212
213 foreach ($key as $k => $v)
214 {
215 $prefix = (count($this->ar_where) == 0) ? '' : $type;
216
217 if ( ! is_null($v))
218 {
219 if ( ! $this->_has_operator($k))
220 {
221 $k .= ' =';
222 }
223
224 $v = ' '.$this->escape($v);
225 }
226
227 $this->ar_where[] = $prefix.$k.$v;
228 }
229 return $this;
230 }
231
232
233
234 // --------------------------------------------------------------------
235
236 /**
237 * Like
238 *
239 * Generates a %LIKE% portion of the query. Separates
240 * multiple calls with AND
241 *
242 * @access public
243 * @param mixed
244 * @param mixed
245 * @return object
246 */
247 function like($field, $match = '')
248 {
249 return $this->_like($field, $match, 'AND ');
250 }
251
252 // --------------------------------------------------------------------
253
254 /**
255 * OR Like
256 *
257 * Generates a %LIKE% portion of the query. Separates
258 * multiple calls with OR
259 *
260 * @access public
261 * @param mixed
262 * @param mixed
263 * @return object
264 */
265 function orlike($field, $match = '')
266 {
267 return $this->_like($field, $match, 'OR ');
268 }
269
270 // --------------------------------------------------------------------
271
272 /**
273 * Like
274 *
275 * Called by like() or orlike()
276 *
277 * @access private
278 * @param mixed
279 * @param mixed
280 * @param string
281 * @return object
282 */
283 function _like($field, $match = '', $type = 'AND ')
284 {
285 if ( ! is_array($field))
286 {
287 $field = array($field => $match);
288 }
289
290 foreach ($field as $k => $v)
291 {
292 $prefix = (count($this->ar_like) == 0) ? '' : $type;
293
294 $v = $this->escape_str($v);
295
296 $this->ar_like[] = $prefix." $k LIKE '%{$v}%'";
297 }
298 return $this;
299 }
300
301 // --------------------------------------------------------------------
302
303 /**
304 * GROUP BY
305 *
306 * @access public
307 * @param string
308 * @return object
309 */
310 function groupby($by)
311 {
312 if (is_string($by))
313 {
314 $by = explode(',', $by);
315 }
316
317 foreach ($by as $val)
318 {
319 $val = trim($val);
320
321 if ($val != '')
322 $this->ar_groupby[] = $val;
323 }
324 return $this;
325 }
326
327 // --------------------------------------------------------------------
328
329 /**
330 * Sets the HAVING value
331 *
332 * Separates multiple calls with AND
333 *
334 * @access public
335 * @param string
336 * @param string
337 * @return object
338 */
339 function having($key, $value = '')
340 {
341 return $this->_having($key, $value, 'AND ');
342 }
343
344 // --------------------------------------------------------------------
345
346 /**
347 * Sets the OR HAVING value
348 *
349 * Separates multiple calls with OR
350 *
351 * @access public
352 * @param string
353 * @param string
354 * @return object
355 */
356 function orhaving($key, $value = '')
357 {
358 return $this->_having($key, $value, 'OR ');
359 }
360
361 // --------------------------------------------------------------------
362
363 /**
364 * Sets the HAVING values
365 *
366 * Called by having() or orhaving()
367 *
368 * @access private
369 * @param string
370 * @param string
371 * @return object
372 */
373 function _having($key, $value = '', $type = 'AND ')
374 {
375 if ( ! is_array($key))
376 {
377 $key = array($key => $value);
378 }
379
380 foreach ($key as $k => $v)
381 {
382 $prefix = (count($this->ar_having) == 0) ? '' : $type;
383
384 if ($v != '')
385 {
386 $v = ' '.$this->escape($v);
387 }
388
389 $this->ar_having[] = $prefix.$k.$v;
390 }
391 return $this;
392 }
393
394 // --------------------------------------------------------------------
395
396 /**
397 * Sets the ORDER BY value
398 *
399 * @access public
400 * @param string
401 * @param string direction: asc or desc
402 * @return object
403 */
404 function orderby($orderby, $direction = '')
405 {
406 if (trim($direction) != '')
407 {
Derek Allard92782492007-08-10 11:26:01 +0000408 $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
Derek Allard09de1852007-02-14 01:35:56 +0000409 }
410
411 $this->ar_orderby[] = $orderby.$direction;
412 return $this;
413 }
414
415 // --------------------------------------------------------------------
416
417 /**
418 * Sets the LIMIT value
419 *
420 * @access public
421 * @param integer the limit value
422 * @param integer the offset value
423 * @return object
424 */
425 function limit($value, $offset = '')
426 {
427 $this->ar_limit = $value;
428
429 if ($offset != '')
430 $this->ar_offset = $offset;
431
432 return $this;
433 }
434
435 // --------------------------------------------------------------------
436
437 /**
438 * Sets the OFFSET value
439 *
440 * @access public
441 * @param integer the offset value
442 * @return object
443 */
444 function offset($value)
445 {
446 $this->ar_offset = $value;
447 return $this;
448 }
449
450 // --------------------------------------------------------------------
451
452 /**
453 * The "set" function. Allows key/value pairs to be set for inserting or updating
454 *
455 * @access public
456 * @param mixed
457 * @param string
458 * @return object
459 */
460 function set($key, $value = '')
461 {
462 $key = $this->_object_to_array($key);
463
464 if ( ! is_array($key))
465 {
466 $key = array($key => $value);
467 }
468
469 foreach ($key as $k => $v)
470 {
471 $this->ar_set[$k] = $this->escape($v);
472 }
473
474 return $this;
475 }
476
477 // --------------------------------------------------------------------
478
479 /**
480 * Get
481 *
482 * Compiles the select statement based on the other functions called
483 * and runs the query
484 *
485 * @access public
486 * @param string the limit clause
487 * @param string the offset clause
488 * @return object
489 */
490 function get($table = '', $limit = null, $offset = null)
491 {
492 if ($table != '')
493 {
494 $this->from($table);
495 }
496
497 if ( ! is_null($limit))
498 {
499 $this->limit($limit, $offset);
500 }
501
502 $sql = $this->_compile_select();
503
504 $result = $this->query($sql);
505 $this->_reset_select();
506 return $result;
507 }
508
509 // --------------------------------------------------------------------
510
511 /**
512 * GetWhere
513 *
514 * Allows the where clause, limit and offset to be added directly
515 *
516 * @access public
517 * @param string the where clause
518 * @param string the limit clause
519 * @param string the offset clause
520 * @return object
521 */
522 function getwhere($table = '', $where = null, $limit = null, $offset = null)
523 {
524 if ($table != '')
525 {
526 $this->from($table);
527 }
528
529 if ( ! is_null($where))
530 {
531 $this->where($where);
532 }
533
534 if ( ! is_null($limit))
535 {
536 $this->limit($limit, $offset);
537 }
538
539 $sql = $this->_compile_select();
540
541 $result = $this->query($sql);
542 $this->_reset_select();
543 return $result;
544 }
545
546 // --------------------------------------------------------------------
547
548 /**
549 * Insert
550 *
551 * Compiles an insert string and runs the query
552 *
553 * @access public
554 * @param string the table to retrieve the results from
555 * @param array an associative array of insert values
556 * @return object
557 */
558 function insert($table = '', $set = NULL)
559 {
560 if ( ! is_null($set))
561 {
562 $this->set($set);
563 }
564
565 if (count($this->ar_set) == 0)
566 {
567 if ($this->db_debug)
568 {
569 return $this->display_error('db_must_use_set');
570 }
571 return FALSE;
572 }
573
574 if ($table == '')
575 {
576 if ( ! isset($this->ar_from[0]))
577 {
578 if ($this->db_debug)
579 {
580 return $this->display_error('db_must_set_table');
581 }
582 return FALSE;
583 }
584
585 $table = $this->ar_from[0];
586 }
587
588 $sql = $this->_insert($this->dbprefix.$table, array_keys($this->ar_set), array_values($this->ar_set));
589
590 $this->_reset_write();
591 return $this->query($sql);
592 }
593
594 // --------------------------------------------------------------------
595
596 /**
597 * Update
598 *
599 * Compiles an update string and runs the query
600 *
601 * @access public
602 * @param string the table to retrieve the results from
603 * @param array an associative array of update values
604 * @param mixed the where clause
605 * @return object
606 */
607 function update($table = '', $set = NULL, $where = null)
608 {
609 if ( ! is_null($set))
610 {
611 $this->set($set);
612 }
613
614 if (count($this->ar_set) == 0)
615 {
616 if ($this->db_debug)
617 {
618 return $this->display_error('db_must_use_set');
619 }
620 return FALSE;
621 }
622
623 if ($table == '')
624 {
625 if ( ! isset($this->ar_from[0]))
626 {
627 if ($this->db_debug)
628 {
629 return $this->display_error('db_must_set_table');
630 }
631 return FALSE;
632 }
633
634 $table = $this->ar_from[0];
635 }
636
637 if ($where != null)
638 {
639 $this->where($where);
640 }
641
642 $sql = $this->_update($this->dbprefix.$table, $this->ar_set, $this->ar_where);
643
644 $this->_reset_write();
645 return $this->query($sql);
646 }
647
648 // --------------------------------------------------------------------
649
650 /**
651 * Delete
652 *
653 * Compiles a delete string and runs the query
654 *
655 * @access public
656 * @param string the table to retrieve the results from
657 * @param mixed the where clause
658 * @return object
659 */
660 function delete($table = '', $where = '')
661 {
662 if ($table == '')
663 {
664 if ( ! isset($this->ar_from[0]))
665 {
666 if ($this->db_debug)
667 {
668 return $this->display_error('db_must_set_table');
669 }
670 return FALSE;
671 }
672
673 $table = $this->ar_from[0];
674 }
675
676 if ($where != '')
677 {
678 $this->where($where);
679 }
680
681 if (count($this->ar_where) == 0)
682 {
683 if ($this->db_debug)
684 {
685 return $this->display_error('db_del_must_use_where');
686 }
687 return FALSE;
688 }
689
690 $sql = $this->_delete($this->dbprefix.$table, $this->ar_where);
691
692 $this->_reset_write();
693 return $this->query($sql);
694 }
695
696 // --------------------------------------------------------------------
697
698 /**
699 * Use Table - DEPRECATED
700 *
701 * @deprecated use $this->db->from instead
702 */
703 function use_table($table)
704 {
705 return $this->from($table);
706 return $this;
707 }
708
709 // --------------------------------------------------------------------
710
711 /**
712 * ORDER BY - DEPRECATED
713 *
714 * @deprecated use $this->db->orderby() instead
715 */
716 function order_by($orderby, $direction = '')
717 {
718 return $this->orderby($orderby, $direction);
719 }
720
721 // --------------------------------------------------------------------
722
723 /**
724 * Tests whether the string has an SQL operator
725 *
726 * @access private
727 * @param string
728 * @return bool
729 */
730 function _has_operator($str)
731 {
732 $str = trim($str);
733 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
734 {
735 return FALSE;
736 }
737
738 return TRUE;
739 }
740
741 // --------------------------------------------------------------------
742
743 /**
744 * Compile the SELECT statement
745 *
746 * Generates a query string based on which functions were used.
747 * Should not be called directly. The get() function calls it.
748 *
749 * @access private
750 * @return string
751 */
752 function _compile_select()
753 {
754 $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
755
756 $sql .= (count($this->ar_select) == 0) ? '*' : implode(', ', $this->ar_select);
757
758 if (count($this->ar_from) > 0)
759 {
760 $sql .= "\nFROM ";
761 $sql .= implode(', ', $this->ar_from);
762 }
763
764 if (count($this->ar_join) > 0)
765 {
766 $sql .= "\n";
767 $sql .= implode("\n", $this->ar_join);
768 }
769
770 if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
771 {
772 $sql .= "\nWHERE ";
773 }
774
775 $sql .= implode("\n", $this->ar_where);
776
777 if (count($this->ar_like) > 0)
778 {
779 if (count($this->ar_where) > 0)
780 {
781 $sql .= " AND ";
782 }
783
784 $sql .= implode("\n", $this->ar_like);
785 }
786
787 if (count($this->ar_groupby) > 0)
788 {
789 $sql .= "\nGROUP BY ";
790 $sql .= implode(', ', $this->ar_groupby);
791 }
792
793 if (count($this->ar_having) > 0)
794 {
795 $sql .= "\nHAVING ";
796 $sql .= implode("\n", $this->ar_having);
797 }
798
799 if (count($this->ar_orderby) > 0)
800 {
801 $sql .= "\nORDER BY ";
802 $sql .= implode(', ', $this->ar_orderby);
803
804 if ($this->ar_order !== FALSE)
805 {
806 $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC';
807 }
808 }
809
810 if (is_numeric($this->ar_limit))
811 {
812 $sql .= "\n";
813 $sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
814 }
815
816 return $sql;
817 }
818
819 // --------------------------------------------------------------------
820
821 /**
822 * Object to Array
823 *
824 * Takes an object as input and converts the class variables to array key/vals
825 *
826 * @access public
827 * @param object
828 * @return array
829 */
830 function _object_to_array($object)
831 {
832 if ( ! is_object($object))
833 {
834 return $object;
835 }
836
837 $array = array();
838 foreach (get_object_vars($object) as $key => $val)
839 {
840 if ( ! is_object($val) AND ! is_array($val))
841 {
842 $array[$key] = $val;
843 }
844 }
845
846 return $array;
847 }
848
849 // --------------------------------------------------------------------
850
851 /**
852 * Resets the active record values. Called by the get() function
853 *
854 * @access private
855 * @return void
856 */
857 function _reset_select()
858 {
859 $this->ar_select = array();
860 $this->ar_distinct = FALSE;
861 $this->ar_from = array();
862 $this->ar_join = array();
863 $this->ar_where = array();
864 $this->ar_like = array();
865 $this->ar_groupby = array();
866 $this->ar_having = array();
867 $this->ar_limit = FALSE;
868 $this->ar_offset = FALSE;
869 $this->ar_order = FALSE;
870 $this->ar_orderby = array();
871 }
872
873 // --------------------------------------------------------------------
874
875 /**
876 * Resets the active record "write" values.
877 *
878 * Called by the insert() or update() functions
879 *
880 * @access private
881 * @return void
882 */
883 function _reset_write()
884 {
885 $this->ar_set = array();
886 $this->ar_from = array();
887 $this->ar_where = array();
888 }
889
890}
891
adminac94f382006-09-24 20:28:12 +0000892?>