src/hathoora/grid/grid.php
public static function prepare(&$arrGridPrepare, $arrFormData)
    {   
        #0 add meta info 
        $arrGridPrepare['meta'] = array();
        
        #1 assign a unqiue id to every table, this unique id is used when making ajax calls
        if (!empty($arrGridPrepare['table']['id']))
            $table_id = $arrGridPrepare['table']['id'];
        else if (!empty($arrFormData['hathooraGrid_id']))
            $table_id = $arrGridPrepare['table']['id'];
        else
        {
            $table_id = 'hathooraGrid_' . rand(9,99999999);  
            $arrGridPrepare['table']['id'] = $table_id;
        }

        #2a figure out the limit (for SQL)
        if (!empty($arrGridPrepare['table']['limit']['fixed']))
            $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['fixed'];
        else
        {
            // limit
            if (!empty($arrFormData['limit']))
                $arrGridPrepare['limit'] = (int) $arrFormData['limit'];
           
            // default limit
            else if (!empty($arrGridPrepare['table']['limit']['default']) && empty($arrFormData['limit']))
                $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['default'];
        }

        // max limit
        if (!empty($arrGridPrepare['table']['limit']['max']) && !empty($arrGridPrepare['limit']) && $arrGridPrepare['limit'] > $arrGridPrepare['table']['limit']['max'])
            $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['max'];

        // cap limit when not able to assign a limit
        if (empty($arrGridPrepare['limit']))
            $arrGridPrepare['limit'] = 100;

        #2b figure out page (for SQL & pagination)
        if (empty($arrGridPrepare['page']))
        {
            $page = !empty($arrFormData['page']) ? (int) $arrFormData['page'] : 1;
            $arrGridPrepare['page'] = $page;
        }
        
        #2c figure out page (for SQL & pagination)
        if (empty($arrGridPrepare['start']))
        {
            $start = ($arrGridPrepare['page'] - 1) * $arrGridPrepare['limit'];
            if ($start < 1) $start = 0;
            $arrGridPrepare['start'] = $start;
        }

        
        #3 figure out the columns we need to display in table
        $tableFieldsAvailable = isset($arrGridPrepare['table']['fields']['available']) ? $arrGridPrepare['table']['fields']['available'] : null;
        if (is_array($tableFieldsAvailable))
        {
            // @todo check file before loading..
            #sqlLoadClassTest(true);
            $callable = is_callable($tableFieldsAvailable);
            #sqlLoadClassTest(false);
            
            if ($callable)
            {
                #3a figure out which columns are actually available for selection
                $arrFieldsAvailable = call_user_func_array($tableFieldsAvailable, array());
                
                // any jail?
                $arrFieldsPossibleJail = isset($arrGridPrepare['table']['fields']['jail']) ? $arrGridPrepare['table']['fields']['jail'] : null;
                $arrFieldsJail = array(); // fill it with confirm jailed fields
                if (is_array($arrFieldsAvailable) && is_array($arrFieldsPossibleJail))
                {
                    foreach ($arrFieldsPossibleJail as $field)
                    {
                        if (isset($arrFieldsAvailable[$field]))
                            $arrFieldsJail[$field] =& $arrFieldsAvailable[$field];
                    }
                }
                
                // these are the fields that are available for selection
                if  (count($arrFieldsJail))
                    $arrFields =& $arrFieldsJail;
                else
                    $arrFields =& $arrFieldsAvailable;
                    
                #3b prepare the column array which is used by renderTable to draw table
                if (is_array($arrFields))
                {
                    $arrColumnsPossibleType = 'indexed';
                    // dynamic columns that are passed by the ajax call?
                    if (!empty($arrGridPrepare['table']['fields']['dynamic']) && !empty($arrFormData['columns']) && is_array($arrFormData['columns']))
                    {
                        $arrColumnsPossible = $arrFormData['columns'];
                        $arrColumnsPossibleType = 'associative';
                    }
                    // default columns specified
                    else if (!empty($arrGridPrepare['table']['fields']['default']) && count($arrGridPrepare['table']['fields']['default']))
                        $arrColumnsPossible = $arrGridPrepare['table']['fields']['default'];

                    // if still not able to figure out possible columns then use $arrFields
                    if (empty($arrColumnsPossible) || !count($arrColumnsPossible))
                    {
                        $arrColumnsPossible = $arrFields;
                        $arrColumnsPossibleType = 'associative';
                    }

                    #3c now figure out among the possible columns which ones are actually defined and can be used
                    if (is_array($arrColumnsPossible))
                    {
                        foreach($arrColumnsPossible as $field => $vfield)
                        {
                            // be careful because can have associative or indexed array based on how it was prepared
                            if ($arrColumnsPossibleType == 'indexed')
                                $field = $vfield;

                            if (isset($arrFields[$field]) && is_array($arrFields[$field]))
                            {
                                $arrField =& $arrFields[$field];

                                // name of the field?
                                if (!empty($arrField['name']))
                                {
                                    $cleanName = $arrField['name'];

                                    # @todo only when CSV is output..
                                    #if ($arrGridPrepare['table']['output'] != 'html')
                                    #    $cleanName = self::cleanString($arrField['name']);

                                    if ($cleanName)
                                        $arrField['name'] = $cleanName;
                                }

                                if (empty($arrField['name']))
                                    $arrField['name'] = $field;

                                if (!array_key_exists('canDel', $arrField))
                                    $arrField['canDel'] = true;

                                // set the default value of dbField
                                if (!array_key_exists('dbField', $arrField))
                                    $arrField['dbField'] = $field;

                                // any dependencies?
                                if (isset($arrField['dependency']) && is_array($arrField['dependency']))
                                    self::prepareDependencyHandler('column', $field, $arrField, $arrGridPrepare, $arrFormData);
                                if (!empty($arrField['dbField']))
                                    $arrGridPrepare['selectField'][$arrField['dbField']] = $arrField['dbField'];


                                $arrGridPrepare['table']['columns'][$field] =& $arrField;
                                $arrGridPrepare['table']['columnsJS'][$field] = array(
                                                                                    'field' => $field,
                                                                                    'name' => isset($arrField['name']) ? $arrField['name'] : $field,
                                                                                    'sort' => isset($arrField['sort']) ? $arrField['sort'] : 0,
                                                                                );
                            }
                        }
                    }
                }
            }
        }

        #4 sort & order
        if (!empty($arrFormData['sort']))
        {
            // is the field even marked sortable?
            if (!empty($arrFields[$arrFormData['sort']]['sort']))
            {
                // field has dbField?
                if (!empty($arrFields[$arrFormData['sort']]['dbField']))
                    $arrGridPrepare['sort'] = self::removeNand($arrFields[$arrFormData['sort']]['dbField']);
                else
                    $arrGridPrepare['sort'] = self::removeNand($arrFormData['sort']);

                if (!empty($arrFormData['order']))
                    $arrGridPrepare['order'] = $arrFormData['order'];
            }
        }

        // default sort & order
        if (empty($arrGridPrepare['sort']) && !empty($arrGridPrepare['table']['sort']['default']))
            $arrGridPrepare['sort'] = $arrGridPrepare['table']['sort']['default'];

        if (empty($arrGridPrepare['order']) && !empty($arrGridPrepare['table']['order']['default']))
            $arrGridPrepare['order'] = $arrGridPrepare['table']['order']['default'];

        if (empty($arrGridPrepare['sort']) && !empty($arrGridPrepare['order']))
            $arrGridPrepare['order'] = 'desc';

        #5 output
        if (empty($arrGridPrepare['table']['output']) && !empty($arrFormData['output']))
            $arrGridPrepare['table']['output'] = $arrFormData['output'];
        if (empty($arrGridPrepare['table']['output']))
            $arrGridPrepare['table']['output'] = 'html';

        #6a search fields
        // fields a user can search on
        $arrSearchableFields = array();

        // get the columns that are searchable, first from the ['table']['column']['fields']
        if (!empty($arrFields) && is_array($arrFields))
        {
            foreach ($arrFields as $_field => $_arrField)
            {
                if (!empty($_arrField['search']) && is_array($_arrField['search']))
                {
                    if (!empty($_arrField['search']['type']))
                    {
                        if (!empty($_arrField['search']['operations']))
                        {
                            $_operations = explode(',', $_arrField['search']['operations']);
                            $_searchArr = array();
                            foreach($_operations as $_operation)
                            {
                                $_operation = trim($_operation);
                                $_searchArr[$_operation] = $_operation;
                            }

                            $arrSearchableFields[$_field] = $_searchArr;
                            $arrGridPrepare['table']['columnsJS'][$field]['search'] = $_searchArr;
                        }
                    }
                }
            }
        }

        #6 where criteria
        $arrWherePossible = null;
        if (!empty($arrFormData['where']) && is_array($arrFormData['where']))
            $arrWherePossible =& $arrFormData['where'];
        $arrWhere = array(); // fields that are searched

        if (is_array($arrWherePossible) && count($arrSearchableFields))
        {
            // loop over where criteria and make sure the fields are searchable so we can prepare where criteria
            foreach($arrWherePossible as $where => $value)
            {   
                if (preg_match('/[a-zA-z0-9_\.]+(|:)/i', $where, $arrMatch))
                {
                    $field = $arrMatch[0];
                    
                    // is field even searchable?
                    if (!empty($arrSearchableFields[$field]) && is_array($arrSearchableFields[$field]))
                    {
                        $arrField = $arrFields[$field];
                        if (!empty($arrField['dependency']) && is_array($arrField['dependency']))
                            self::prepareDependencyHandler('where', $field, $arrField, $arrGridPrepare, $arrFormData);
                            
                        $arrWhere[$where] = $value;
                    }
                }
            }
        }

        // make rowWhere the same as totalWhere
        if (count($arrWhere))
            $arrGridPrepare['whereTotal'] = $arrGridPrepare['whereRow'] = $arrWhere;
        
        // ajax URL
        if (empty($arrGridPrepare['table']['sort']['url']))
            $arrGridPrepare['table']['sort']['url'] = $_SERVER['REQUEST_URI'];

        // cleanup duplicate for duplicate params
        // @http://stackoverflow.com/questions/2613063/remove-duplicate-from-string-in-php
        if ($arrGridPrepare['table']['sort']['url'])
        {
            $url = parse_url($arrGridPrepare['table']['sort']['url'], PHP_URL_PATH);
            $params = parse_url($arrGridPrepare['table']['sort']['url'], PHP_URL_QUERY);
            if ($params)
            {
                parse_str($params, $paramsArr);
                $params = http_build_query($paramsArr);
            }

            $arrGridPrepare['table']['sort']['url'] = $url . ($params ? '?'. $params : null);
        }

        // ajax requesy?
        if (!array_key_exists('pajax', $arrGridPrepare) && container::getRequest()->isAjax())
            $arrGridPrepare['pajax'] = true;
    }
public static function prepare(&$arrGridPrepare, $arrFormData)
    {   
        #0 add meta info 
        $arrGridPrepare['meta'] = array();
        
        #1 assign a unqiue id to every table, this unique id is used when making ajax calls
        if (!empty($arrGridPrepare['table']['id']))
            $table_id = $arrGridPrepare['table']['id'];
        else if (!empty($arrFormData['hathooraGrid_id']))
            $table_id = $arrGridPrepare['table']['id'];
        else
        {
            $table_id = 'hathooraGrid_' . rand(9,99999999);  
            $arrGridPrepare['table']['id'] = $table_id;
        }

        #2a figure out the limit (for SQL)
        if (!empty($arrGridPrepare['table']['limit']['fixed']))
            $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['fixed'];
        else
        {
            // limit
            if (!empty($arrFormData['limit']))
                $arrGridPrepare['limit'] = (int) $arrFormData['limit'];
           
            // default limit
            else if (!empty($arrGridPrepare['table']['limit']['default']) && empty($arrFormData['limit']))
                $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['default'];
        }

        // max limit
        if (!empty($arrGridPrepare['table']['limit']['max']) && !empty($arrGridPrepare['limit']) && $arrGridPrepare['limit'] > $arrGridPrepare['table']['limit']['max'])
            $arrGridPrepare['limit'] = $arrGridPrepare['table']['limit']['max'];

        // cap limit when not able to assign a limit
        if (empty($arrGridPrepare['limit']))
            $arrGridPrepare['limit'] = 100;

        #2b figure out page (for SQL & pagination)
        if (empty($arrGridPrepare['page']))
        {
            $page = !empty($arrFormData['page']) ? (int) $arrFormData['page'] : 1;
            $arrGridPrepare['page'] = $page;
        }
        
        #2c figure out page (for SQL & pagination)
        if (empty($arrGridPrepare['start']))
        {
            $start = ($arrGridPrepare['page'] - 1) * $arrGridPrepare['limit'];
            if ($start < 1) $start = 0;
            $arrGridPrepare['start'] = $start;
        }

        
        #3 figure out the columns we need to display in table
        $tableFieldsAvailable = isset($arrGridPrepare['table']['fields']['available']) ? $arrGridPrepare['table']['fields']['available'] : null;
        if (is_array($tableFieldsAvailable))
        {
            // @todo check file before loading..
            #sqlLoadClassTest(true);
            $callable = is_callable($tableFieldsAvailable);
            #sqlLoadClassTest(false);
            
            if ($callable)
            {
                #3a figure out which columns are actually available for selection
                $arrFieldsAvailable = call_user_func_array($tableFieldsAvailable, array());
                
                // any jail?
                $arrFieldsPossibleJail = isset($arrGridPrepare['table']['fields']['jail']) ? $arrGridPrepare['table']['fields']['jail'] : null;
                $arrFieldsJail = array(); // fill it with confirm jailed fields
                if (is_array($arrFieldsAvailable) && is_array($arrFieldsPossibleJail))
                {
                    foreach ($arrFieldsPossibleJail as $field)
                    {
                        if (isset($arrFieldsAvailable[$field]))
                            $arrFieldsJail[$field] =& $arrFieldsAvailable[$field];
                    }
                }
                
                // these are the fields that are available for selection
                if  (count($arrFieldsJail))
                    $arrFields =& $arrFieldsJail;
                else
                    $arrFields =& $arrFieldsAvailable;
                    
                #3b prepare the column array which is used by renderTable to draw table
                if (is_array($arrFields))
                {
                    $arrColumnsPossibleType = 'indexed';
                    // dynamic columns that are passed by the ajax call?
                    if (!empty($arrGridPrepare['table']['fields']['dynamic']) && !empty($arrFormData['columns']) && is_array($arrFormData['columns']))
                    {
                        $arrColumnsPossible = $arrFormData['columns'];
                        $arrColumnsPossibleType = 'associative';
                    }
                    // default columns specified
                    else if (!empty($arrGridPrepare['table']['fields']['default']) && count($arrGridPrepare['table']['fields']['default']))
                        $arrColumnsPossible = $arrGridPrepare['table']['fields']['default'];

                    // if still not able to figure out possible columns then use $arrFields
                    if (empty($arrColumnsPossible) || !count($arrColumnsPossible))
                    {
                        $arrColumnsPossible = $arrFields;
                        $arrColumnsPossibleType = 'associative';
                    }

                    #3c now figure out among the possible columns which ones are actually defined and can be used
                    if (is_array($arrColumnsPossible))
                    {
                        foreach($arrColumnsPossible as $field => $vfield)
                        {
                            // be careful because can have associative or indexed array based on how it was prepared
                            if ($arrColumnsPossibleType == 'indexed')
                                $field = $vfield;

                            if (isset($arrFields[$field]) && is_array($arrFields[$field]))
                            {
                                $arrField =& $arrFields[$field];

                                // name of the field?
                                if (!empty($arrField['name']))
                                {
                                    $cleanName = $arrField['name'];

                                    # @todo only when CSV is output..
                                    #if ($arrGridPrepare['table']['output'] != 'html')
                                    #    $cleanName = self::cleanString($arrField['name']);

                                    if ($cleanName)
                                        $arrField['name'] = $cleanName;
                                }

                                if (empty($arrField['name']))
                                    $arrField['name'] = $field;

                                if (!array_key_exists('canDel', $arrField))
                                    $arrField['canDel'] = true;

                                // set the default value of dbField
                                if (!array_key_exists('dbField', $arrField))
                                    $arrField['dbField'] = $field;

                                // any dependencies?
                                if (isset($arrField['dependency']) && is_array($arrField['dependency']))
                                    self::prepareDependencyHandler('column', $field, $arrField, $arrGridPrepare, $arrFormData);
                                if (!empty($arrField['dbField']))
                                    $arrGridPrepare['selectField'][$arrField['dbField']] = $arrField['dbField'];


                                $arrGridPrepare['table']['columns'][$field] =& $arrField;
                                $arrGridPrepare['table']['columnsJS'][$field] = array(
                                                                                    'field' => $field,
                                                                                    'name' => isset($arrField['name']) ? $arrField['name'] : $field,
                                                                                    'sort' => isset($arrField['sort']) ? $arrField['sort'] : 0,
                                                                                );
                            }
                        }
                    }
                }
            }
        }

        #4 sort & order
        if (!empty($arrFormData['sort']))
        {
            // is the field even marked sortable?
            if (!empty($arrFields[$arrFormData['sort']]['sort']))
            {
                // field has dbField?
                if (!empty($arrFields[$arrFormData['sort']]['dbField']))
                    $arrGridPrepare['sort'] = self::removeNand($arrFields[$arrFormData['sort']]['dbField']);
                else
                    $arrGridPrepare['sort'] = self::removeNand($arrFormData['sort']);

                if (!empty($arrFormData['order']))
                    $arrGridPrepare['order'] = $arrFormData['order'];
            }
        }

        // default sort & order
        if (empty($arrGridPrepare['sort']) && !empty($arrGridPrepare['table']['sort']['default']))
            $arrGridPrepare['sort'] = $arrGridPrepare['table']['sort']['default'];

        if (empty($arrGridPrepare['order']) && !empty($arrGridPrepare['table']['order']['default']))
            $arrGridPrepare['order'] = $arrGridPrepare['table']['order']['default'];

        if (empty($arrGridPrepare['sort']) && !empty($arrGridPrepare['order']))
            $arrGridPrepare['order'] = 'desc';

        #5 output
        if (empty($arrGridPrepare['table']['output']) && !empty($arrFormData['output']))
            $arrGridPrepare['table']['output'] = $arrFormData['output'];
        if (empty($arrGridPrepare['table']['output']))
            $arrGridPrepare['table']['output'] = 'html';

        #6a search fields
        // fields a user can search on
        $arrSearchableFields = array();

        // get the columns that are searchable, first from the ['table']['column']['fields']
        if (!empty($arrFields) && is_array($arrFields))
        {
            foreach ($arrFields as $_field => $_arrField)
            {
                if (!empty($_arrField['search']) && is_array($_arrField['search']))
                {
                    if (!empty($_arrField['search']['type']))
                    {
                        if (!empty($_arrField['search']['operations']))
                        {
                            $_operations = explode(',', $_arrField['search']['operations']);
                            $_searchArr = array();
                            foreach($_operations as $_operation)
                            {
                                $_operation = trim($_operation);
                                $_searchArr[$_operation] = $_operation;
                            }

                            $arrSearchableFields[$_field] = $_searchArr;
                            $arrGridPrepare['table']['columnsJS'][$field]['search'] = $_searchArr;
                        }
                    }
                }
            }
        }

        #6 where criteria
        $arrWherePossible = null;
        if (!empty($arrFormData['where']) && is_array($arrFormData['where']))
            $arrWherePossible =& $arrFormData['where'];
        $arrWhere = array(); // fields that are searched

        if (is_array($arrWherePossible) && count($arrSearchableFields))
        {
            // loop over where criteria and make sure the fields are searchable so we can prepare where criteria
            foreach($arrWherePossible as $where => $value)
            {   
                if (preg_match('/[a-zA-z0-9_\.]+(|:)/i', $where, $arrMatch))
                {
                    $field = $arrMatch[0];
                    
                    // is field even searchable?
                    if (!empty($arrSearchableFields[$field]) && is_array($arrSearchableFields[$field]))
                    {
                        $arrField = $arrFields[$field];
                        if (!empty($arrField['dependency']) && is_array($arrField['dependency']))
                            self::prepareDependencyHandler('where', $field, $arrField, $arrGridPrepare, $arrFormData);
                            
                        $arrWhere[$where] = $value;
                    }
                }
            }
        }

        // make rowWhere the same as totalWhere
        if (count($arrWhere))
            $arrGridPrepare['whereTotal'] = $arrGridPrepare['whereRow'] = $arrWhere;
        
        // ajax URL
        if (empty($arrGridPrepare['table']['sort']['url']))
            $arrGridPrepare['table']['sort']['url'] = $_SERVER['REQUEST_URI'];

        // cleanup duplicate for duplicate params
        // @http://stackoverflow.com/questions/2613063/remove-duplicate-from-string-in-php
        if ($arrGridPrepare['table']['sort']['url'])
        {
            $url = parse_url($arrGridPrepare['table']['sort']['url'], PHP_URL_PATH);
            $params = parse_url($arrGridPrepare['table']['sort']['url'], PHP_URL_QUERY);
            if ($params)
            {
                parse_str($params, $paramsArr);
                $params = http_build_query($paramsArr);
            }

            $arrGridPrepare['table']['sort']['url'] = $url . ($params ? '?'. $params : null);
        }

        // ajax requesy?
        if (!array_key_exists('pajax', $arrGridPrepare) && container::getRequest()->isAjax())
            $arrGridPrepare['pajax'] = true;
    }
This function prepare the grid array by setting limit, sorting, selected fields, row criteria etc..
This function also makes sure that a user cannot user a property (sort, search, select etc..) when it is
not specified in the $arrGridPrepare

Once the data has been processed it is then ready to be handed off to sqlRun() function

@param array $arrGridPrepare
@param array $arrFormData (which is usually via GET or POST)