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