[eluser]Jon L[/eluser]
Thanks for feedback, and just a warning, I'm writing this while working so I may not have a fully coherent post ;-)
Re: named groups - I thought about using named groups, but I'm not sure now I want to redo the logic :-)
Re: _or consistency - maybe instead allow where_group('OR')? But I'm not a fan of allowing strings unless absolutely necessary.
Really, while I like the result, and the behind-the-scenes "magic" that I conjured up, I don't like the visual implementation either, as mixing the where_group() calls in and out, looks ugly and throws off the visual code flow.
To give you an idea of how this method is implemented, there is a multi-dimensional array that is built on-the-fly as group_where() gets called. The "level" (read: depth) is sync'd with the group/ungroup calls.
When adding a new where() statement, the statement gets inserted into the last occurrence of the array (while considering depth).
Obtuse eh? :-D
Here's the behind-the-scenes snippet, input is appreciated.
Notes: _add_where() is now used by _where(), _like(), _between(), etc.
_where_level is established as having a value of 0 to begin with.
cache for the where array is currently not implemented.
When a group_where() is called, it inserts an empty array(), which holds the place for subsequent where string injections.
And just a note, the key for each array occurrence, is either AND, or OR, which is used to determine what value should precede a generated () section.
Code:
/**
* Group Where
*
* Alias of group_where_and(), increments the depth
*
* @access public
* @return none
*/
public function group_where()
{
$this->group_where_and();
}
// --------------------------------------------------------------------
/**
* Group Where (and)
*
* Increments the depth
*
* @access public
* @return none
*/
public function group_where_and()
{
$this->_group_where('AND');
}
// --------------------------------------------------------------------
/**
* Group Where (or)
*
* Increments the depth
*
* @access public
* @return none
*/
public function group_where_or()
{
$this->_group_where('OR');
}
// --------------------------------------------------------------------
/**
* Group Where
*
* Increments the depth
*
* @access protected
* @param string $type
* @return none
*/
protected function _group_where($type = 'AND')
{
$this->_add_where($type);
$this->_where_level+=2;
}
// --------------------------------------------------------------------
/**
* UnGroup Where
*
* Decrements the depth
*
* @access public
* @return none
*/
public function ungroup_where()
{
if($this->_where_level>=2) $this->_where_level-=2;
else $this->_where_level = 0;
}
// --------------------------------------------------------------------
/**
* Adds an entry to the WHERE array
*
* @todo Need to solve cached WHERE dilemma
*
* @access protected
* @param string $type AND,OR
* @param mixed $condition String or Array to be used for nesting
* @return none
*/
protected function _add_where($type, $condition = array())
{
$type = trim($type);
$arr =& $this->_get_last($this->ar_where, $this->_where_level);
array_push($arr, array($type, $condition));
/*if ($this->ar_caching === TRUE)
{
$arr =& $this->_get_last($this->ar_cache_where, $this->_where_level);
array_push($arr, array($type, $condition));
$this->ar_cache_exists[] = 'where';
}*/
}
// --------------------------------------------------------------------
/**
* Gets the last entry in an array, recursion determined by level
*
* @access protected
* @param array $arr Referenced array to search
* @param integer $level How many levels to recurse
* @return mixed Returns a reference to the entry that is found
*/
protected function &_get_last(&$arr, $level=0)
{
if($level==0 || (is_array($arr) && empty($arr)) || !is_array($arr)) {
return $arr;
}
$pos = count($arr);
if($pos>0) $pos--;
$level--;
return $this->_get_last($arr[$pos], $level);
}
// --------------------------------------------------------------------
/**
* Flattens a multi-dimensional array down into a string
* Currently built specifically for use on building WHERE string
*
* @todo Need to make this method generic enough that it can be used for JOINs, etc.
*
* @access protected
* @param array $arr
* @return string
*/
protected function _flatten($arr)
{
$return = '';
foreach($arr AS $entry)
{
list($k, $v) = $entry;
if(!empty($v))
{
if(!empty($return) && is_string($k))
{
$return .= ' ' . $k . ' ';
}
if(is_array($v))
{
$return .= '(';
$return .= $this->_flatten($v);
$return .= ')';
}
else
{
$return .= $v;
}
}
}
return $return;
}