1<?php defined('SYSPATH') OR die('No direct script access.');
2/**
3 * Database query builder for JOIN statements. See [Query Builder](/database/query/builder) for usage and examples.
4 *
5 * @package    Kohana/Database
6 * @category   Query
7 * @author     Kohana Team
8 * @copyright  (c) 2008-2009 Kohana Team
9 * @license    http://kohanaphp.com/license
10 */
11class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
12
13	// Type of JOIN
14	protected $_type;
15
16	// JOIN ...
17	protected $_table;
18
19	// ON ...
20	protected $_on = array();
21
22	// USING ...
23	protected $_using = array();
24
25	/**
26	 * Creates a new JOIN statement for a table. Optionally, the type of JOIN
27	 * can be specified as the second parameter.
28	 *
29	 * @param   mixed   $table  column name or array($column, $alias) or object
30	 * @param   string  $type   type of JOIN: INNER, RIGHT, LEFT, etc
31	 * @return  void
32	 */
33	public function __construct($table, $type = NULL)
34	{
35		// Set the table to JOIN on
36		$this->_table = $table;
37
38		if ($type !== NULL)
39		{
40			// Set the JOIN type
41			$this->_type = (string) $type;
42		}
43	}
44
45	/**
46	 * Adds a new condition for joining.
47	 *
48	 * @param   mixed   $c1  column name or array($column, $alias) or object
49	 * @param   string  $op  logic operator
50	 * @param   mixed   $c2  column name or array($column, $alias) or object
51	 * @return  $this
52	 */
53	public function on($c1, $op, $c2)
54	{
55		if ( ! empty($this->_using))
56		{
57			throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
58		}
59
60		$this->_on[] = array($c1, $op, $c2);
61
62		return $this;
63	}
64
65	/**
66	 * Adds a new condition for joining.
67	 *
68	 * @param   string  $columns  column name
69	 * @return  $this
70	 */
71	public function using($columns)
72	{
73		if ( ! empty($this->_on))
74		{
75			throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
76		}
77
78		$columns = func_get_args();
79
80		$this->_using = array_merge($this->_using, $columns);
81
82		return $this;
83	}
84
85	/**
86	 * Compile the SQL partial for a JOIN statement and return it.
87	 *
88	 * @param   mixed  $db  Database instance or name of instance
89	 * @return  string
90	 */
91	public function compile($db = NULL)
92	{
93		if ( ! is_object($db))
94		{
95			// Get the database instance
96			$db = Database::instance($db);
97		}
98
99		if ($this->_type)
100		{
101			$sql = strtoupper($this->_type).' JOIN';
102		}
103		else
104		{
105			$sql = 'JOIN';
106		}
107
108		// Quote the table name that is being joined
109		$sql .= ' '.$db->quote_table($this->_table);
110
111		if ( ! empty($this->_using))
112		{
113			// Quote and concat the columns
114			$sql .= ' USING ('.implode(', ', array_map(array($db, 'quote_column'), $this->_using)).')';
115		}
116		else
117		{
118			$conditions = array();
119			foreach ($this->_on as $condition)
120			{
121				// Split the condition
122				list($c1, $op, $c2) = $condition;
123
124				if ($op)
125				{
126					// Make the operator uppercase and spaced
127					$op = ' '.strtoupper($op);
128				}
129
130				// Quote each of the columns used for the condition
131				$conditions[] = $db->quote_column($c1).$op.' '.$db->quote_column($c2);
132			}
133
134			// Concat the conditions "... AND ..."
135			$sql .= ' ON ('.implode(' AND ', $conditions).')';
136		}
137
138		return $sql;
139	}
140
141	public function reset()
142	{
143		$this->_type =
144		$this->_table = NULL;
145
146		$this->_on = array();
147	}
148
149} // End Database_Query_Builder_Join
150