建议的方式是把表名和条件分成两个参数,JOIN方法设三个参数:JOIN(表名,关联条件,关联类型)。代码如下:
/**
* 查询SQL组装 join
* @access public
* @param mixed $join 关联表名
* @param mixed $condition 关联条件
* @param string $type JOIN类型
* @return Model
*/
public function join($join,$condition,$type='INNER') {
if(empty($join)) return $this;
if (!isset($condition)) {
if (is_array($join) && is_array(current($join))) {
// 如果为组数,则循环调用join
foreach ($join as $key => $value) {
if (is_array($value) && 2 <= count($value)) {
$this->join($value[0],$value[1],isset($value[2])?$value[2]:$type);
}
}
} else {
$this->_join($join,$condition); // 兼容原来的join写法
}
} elseif (in_array($condition, array('INNER','LEFT','RIGHT','ALL'))) {
$this->_join($join,$condition); // 兼容原来的join写法
} else {
$prefix = $this->tablePrefix;
if (is_array($join)) {
if (0 !== key($join)) {
$table = key($join) . ' ' . current($join);
} else {
$table = current($join);
}
if (!isset($join[1]) || false != $join[1]) {
$table = $prefix . $table;
}
} else {
$join = ltrim($join);
if (0 === strpos($join, '__')) {
//将__TABLE_NAME__字符串替换成带前缀的表名
$table = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $join);
} elseif (false === strpos($join, '(') && 0 !== strpos($join, $prefix)) {
$table = $prefix . $join;
} else {
$table = $join;
}
}
if (is_array($condition)) {
$condition = implode(' AND ', $condition);
}
$this->options['join'][] = $type.' JOIN '.$table.' ON '.$condition;
}
return $this;
}
/**
* 查询SQL组装 _join
* @access public
* @param mixed $join
* @param string $type JOIN类型
* @return Model
*/
public function _join($join,$type='INNER') {
$prefix = $this->tablePrefix;
if(is_array($join)) {
foreach ($join as $key=>&$_join){
$_join = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $_join);
$_join = false !== stripos($_join,'JOIN')? $_join : $type.' JOIN ' .$_join;
}
$this->options['join'] = $join;
}elseif(!empty($join)) {
//将__TABLE_NAME__字符串替换成带前缀的表名
$join = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $join);
$this->options['join'][] = false !== stripos($join,'JOIN')? $join : $type.' JOIN '.$join;
}
return $this;
}为了与原来的JOIN方法兼容,所以把Model类中原JOIN方法改名成_join,并判断join方法第二个参数,值为('INNER','LEFT','RIGHT','ALL')中的一个时就调用_join方法。此时调用方法就与原来的一样,关联条件需要和表名写在一起。调用说明:
M('User')->alias('u')->join('group g', 'u.id=g.user_id')->select();
/* select * form tp_user u join tp_group g on u.id=g.user_id; */group表自动加上了表前缀tp_。第一个参数也可以是一个数组,如:
M('User')->alias('u')->join(array('group'=>'g'), 'u.id=g.user_id')->select();
/* select * form tp_user u join tp_group g on u.id=g.user_id; */生成的sql语句和前面的一样。如果不想添加默认的表前缀,可以这样调用:
M('User')->alias('u')->join(array('group'=>'g', false), 'u.id=g.user_id')->select();
/* select * form tp_user u join group g on u.id=g.user_id; */此时group不再自动加上前缀。支持多个join连写,如:
M('User')->alias('u')->join('group g', 'u.id=g.user_id')->join('role r', 'g.id=r.group_id')->select();也可以以数组形式调用$join = array(array('group g', 'u.id=g.user_id'), array('role r', 'g.id=r.group_id')); M('User')->alias('u')->join($join)->select();此时join方法不得传入第二和第三参数。 