Welcome Guest, Not a member yet? Register   Sign In
My CI Hacks Pt 1
#1

[eluser]vijinho[/eluser]
I've been using CI to develop a new site and working around certain issues I encountered I present some of the hacks I have made.


a) I wanted to get the prepared and compiled SQL statement from my active record commands without actually running it and I wrote this method to do so.

File: system/database/db_active_rec.php

Code:
/**
     * Get The Compiled SQL Statement
     *
     * Compiles the select statement based on the other functions called
     * and runs the query
     *
     * @access  public
     * @param   string  the limit clause
     * @param   string  the offset clause
     * @return  object
     */
    function get_compiled_sql($table = '', $limit = null, $offset = null)
    {
        if ($table != '')
        {
            $this->from($table);
        }

        if ( ! is_null($limit))
        {
            $this->limit($limit, $offset);
        }

        $sql = $this->_compile_select();

        $this->_reset_select();
        return $sql;
    }


b) I needed to get a count of the number of rows only for the current active record query WITHOUT pulling back every single row of the db into an array and then counting that array.

File: system/database/db_active_rec.php

Code:
function get_nrows($table = '', $limit = null, $offset = null)
    {
        if ($table != '')
        {
                $this->from($table);
        }

        if ( ! is_null($limit))
        {
                $this->limit($limit, $offset);
        }

        $sql = $this->_compile_select();
        $this->_reset_select();

        $sql = 'SELECT COUNT(*) AS rows FROM (' . $sql . ') results';

        // return the count value
        $query = $this->query($sql);
        $result = $query->result_array();
        if (is_array($result)) {
            $result = $result[0]['rows'];
        }
        $this->_reset_select();
        return $result;
    }


c) I needed to perform a mysql "SOUNDS LIKE" (SOUNDEX) search so I modified the active record class to have a new clause (copying the like parts and adding new methods and code where necessary) such that we I got something like this. Probably should have been in the mysqli driver than there.

File: system/database/db_active_rec.php

Code:
$this->ar_soundslike[] = $prefix." $k SOUNDS LIKE '{$v}'";

d)
I wanted a bit more flexibility from result_array() so that

a) When getting the result array, I found I was having to loop over the results a 2nd time in order to set the key for the array results, e.g. for id fields which was quite wasteful, so I added an option to specify which field of the database resultset to use as the array key instead

b) I had to process very large tables, some of over 100,000 records so I wanted to be able to loop over the resultset with a db pointer rather than use up all the memory, so I added a 2nd option, $pointeronly which returns just the DB pointer, which allows my controller to then loop over the large result set using

while ($result = $rp->_fetch_assoc())

Where $rp is the returned result pointer

File: system/database/DB_result.php

Code:
/**
     * Query result.  "array" version.
     *
     * @access    public
     * @return    array
     */
    function result_array($indexfield = null, $pointeronly = null)
    {
        if (count($this->result_array) > 0)
        {
            return $this->result_array;
        }

        // In the event that query caching is on the result_id variable
        // will return FALSE since there isn't a valid SQL resource so
        // we'll simply return an empty array.
        if ($this->result_id === FALSE OR $this->num_rows() == 0)
        {
            return array();
        }

        $this->_data_seek(0);
        if (empty($pointeronly)) {
            while ($row = $this->_fetch_assoc())
            {
                if (!empty($indexfield)) {
                    $this->result_array[$row[$indexfield]] = $row;
                } else {
                    $this->result_array[] = $row;
                }
            }
            return $this->result_array;
        } else {
            return $this;
        }
    }

this is continued in next post (exceeded 6000 chars despite the form saying 300 or so remaining for the entire original post!)
#2

[eluser]vijinho[/eluser]
e) I wanted to get the form validation errors and present them in my own way, so I wrote this extension to get back the array of errors:

Code:
class MY_Validation extends CI_Validation {
    function getErrorMessages()
    {
        return $this->_error_array;
    }
}


f) I also wanted error messages for uploads to be handled differently and also to be able to identify if an upload was audio (mp3):

Code:
/**
* FAIL File Uploading Class
*
* @package        CodeIgniter
* @subpackage    Libraries
* @category    Uploads
* @author      Vijay Mahrra
* @link        http://www.ellislab.com/codeigniter/user-guide/libraries/file_uploading.html
*/
class MY_Upload extends CI_Upload
{
    /**
     * Get the error messages
     *
     * @access  public
     * @param   string
     * @param   string
     * @return  array error_msg
     */
    function get_errors()
    {
        return $this->error_msg;
    }

    /**
     * Validate the audio
     *
     * @access    public
     * @return    bool
     */
    function is_audio()
    {
        $mpeg_mimes = array('audio/mpg', 'audio/mp2', 'audio/mp3', 'audio/mpeg');
        if (in_array($this->file_type, $mpeg_mimes))
        {
            $this->file_type = 'audio/mpeg';
        }

        $audio_mimes = array(
                            'audio/mp3',
                            'audio/mpeg'
                           );

        return (in_array($this->file_type, $audio_mimes, TRUE)) ? TRUE : FALSE;
    }
}

g) I ran into the problem about 2/3 through the project of using up the entire session cookie, so thanks due to SeViR ( http://projects.sevir.org ) for the DB extension to store the session data within the database instead with the option to put things in the cookie too.

Thanks to the CI team for a great product, and I hope that these hacks prove useful. I'd love to hear of a better way of doing the above so please let me know your way and how to do things properly Smile
#3

[eluser]johnwbaxter[/eluser]
Oddly enough, i was just about to write my own version of your first method. What excellent timing!

Thanks!
#4

[eluser]xwero[/eluser]
b : i don't think your query works with all databases. mysql versions lower than 5 don't have the ability to process subqueries.

d a : i love the idea of simplifying the output but why d0 you use !empty($indexfield) and not !is_null($indexfield) (or the optimized $indexfield !== null).
I'm also wondering if you use the indexfield as the key will you not overwrite your values?

f : great find with the media group is_video, is_image lays just around the corner

Overall a nice contribution i will be waiting for the second part Smile
#5

[eluser]vijinho[/eluser]
hi.

these are hacks really and perhaps not really optimal, but they did the job. i've been a bit pressed for time to present neat diffs against the latest sourcecode like i have done in the past working with f/oss projects.

using empty() has been a habit of mine for a long time as it's pretty consistent in its results - i basically just wanted to make sure that nothing important, as in empty values, false, empty quotes, 0 got processed and prevented any unexpected results.

the indexfield will overwrite the values but only if the index field is repeated and/or you're not using SELECT DISTINCT

i'm using a primary key for the indexfield where i specify it. if i dont specify any params the default behaviour is the same as for the standard codeigniter version - it returns everything, repeated or not

thanks for the feedback

vijay




Theme © iAndrew 2016 - Forum software by © MyBB