Welcome Guest, Not a member yet? Register   Sign In
Grouping where statements in Active Record - working example - what do you think?
#4

[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;
    }


Messages In This Thread
Grouping where statements in Active Record - working example - what do you think? - by El Forum - 12-10-2008, 10:19 AM



Theme © iAndrew 2016 - Forum software by © MyBB