Welcome Guest, Not a member yet? Register   Sign In
Settings Library
#1

[eluser]Mark LaDoux[/eluser]
After much experimentation, I've written a nice settings class that will pull settings from a database rather than from static files like the config class does in CodeIgniter. I had considered integrating it directly into the config class as a modification, but I wanted to a basic version where I didn't have to worry about overwriting static CodeIgniter config items. Anyway, here it is -->

// added missing semicolon
// made some syntax compatibility corrections thanks to InsiteFX

Code:
<?php

/**
* Setting Class
*
* class accesses application settings from a database.
*/

class setting
{
    private $ci     = null; // holds our CodeIgniter instance
    private $items  = null; // holds an array of our configuration items
    private $table  = null; // table to pull settings from

    /**
     * __cosntruct
     *
     * ensures that class is ready for proper function
     *
     * @access public
     * @return void     method does not return a result
     */

    function __construct()
    {
        // get CodeIgniter instance
        if( $this->ci === null )
        {
            $this->ci =& get_instance();
            $this->ci->config->load('settings'); // let us autoload the settings
            $this->table = $this->ci->config->item('settings_table');
        }

        if( $this->items === null )
        {
            $this->_refresh_items();
        }
    }

    /**
     * _refresh_items
     *
     * refreshes the item array
     *
     * @access private
     * @return void     method does not return a result
     */

    private function _refresh_items()
    {
        $query = $this->ci->db->get($this->table);
        $this->items = array();
        if( $query->num_rows() > 0 )
        {
            while($row = $query->fetch_assoc())
            {
                $item       = $row['item'];
                $value      = $row['value'];

                // do some nice filtering
                if(strtolower($value) == '{{false}}')   $value  = false;
                if(strtolower($value) == '{{true}}')    $value  = true;
                if(strtolower($value) == '{{null}}')    $value  = null;
                if(strtolower($value) == '{{empty}}')   $value  = '';

                $this->items[$item] = $value;
            }
        }
    }

    /**
     * set
     *
     * sets the value of an item in the database
     *
     * @access  public
     * @param   string  $item   item to set
     * @param   string  $value  value of the item
     * @return  void            method does not return a result
     */

    public function set($item, $value)
    {
        // do a little pre-filtering
        if($value === false)    $value = '{{false}}';
        if($value === true)     $value = '{{true}}';
        if($value === null)     $value = '{{null}}';
        if($value == '')        $value = '{{empty}}';

        // quick test
        if(isset($this->items[$item]))
        {
            $this->ci->db->where('item', $item);
            $this->ci->db->update($this->table, array('value' => $value));
        }
        else
        {
            $this->ci->db->insert($this->table, array('item' => $item, 'value' => $value));
        }

        $this->_refresh_items();
    }

    /**
     * get
     *
     * retrieves a setting from the database
     *
     * @access  public
     * @param   string  $item   item to retrieve
     * @return  mixed           value of the item if is set, else false
     */

    public function get($item) {
        if( isset($this->items[$item])) return $this->items[$item];
        return false;
    }
}
#2

[eluser]PhilTem[/eluser]
Nice. Has even less lines of code than my settings-library Big Grin

I just have two questions:
- Why do you do while($row = $query->fetch_assoc()) instead of foreach ( $query->result() as $row )? I'm always using the second way (with caching of course) so I'm just curious why you chose to use the first way.
- Does one really need the checks on if ( $this->ci === null ) and if ( $this->items === null ) One could simple run the get_instance() function in the constructor and the _refresh_items() method without the preceding check, can't we?

I even like the way you store the values for false, true, null and empty. I never really had thought of this one within my settings-library.

If you wanna have a look at an older and almost deprecated version, you can do so here.
#3

[eluser]InsiteFX[/eluser]
Missing semicolon!
Code:
// quick test
        if(isset($this->items[$item]))
        {
            $this->ci->db->where('item', $item);
            $this->ci->db->update($this->table, array('value' => $value));
        }
        else
        {   // the line below is missing the ending semicolon
            $this->ci->db->insert($this->table, array('item' => $item, 'value' => $value))
        }

    private function _refresh_items()
    {
        $query = $this->ci->db->get($this->table);
        $this->items = array();
        if( $query->num_rows > 0 )  // <--- should be $query->num_rows()
        {
            while($row = $query->fetch_assoc())
            {
                $item       = $row['item'];
                $value      = $row['value'];

                // do some nice filtering
                if(strtolower($value) == '{{false}}')   $value  = false;
                if(strtolower($value) == '{{true}}')    $value  = true;
                if(strtolower($value) == '{{null}}')    $value  = null;
                if(strtolower($value) == '{{empty}}')   $value  = '';

                $this->items[$item] = $value;
            }
        }
    }
#4

[eluser]Mark LaDoux[/eluser]
[quote author="PhilTem" date="1328105572"]Nice. Has even less lines of code than my settings-library Big Grin

I just have two questions:
- Why do you do while($row = $query->fetch_assoc()) instead of foreach ( $query->result() as $row )? I'm always using the second way (with caching of course) so I'm just curious why you chose to use the first way.
- Does one really need the checks on if ( $this->ci === null ) and if ( $this->items === null ) One could simple run the get_instance() function in the constructor and the _refresh_items() method without the preceding check, can't we?

I even like the way you store the values for false, true, null and empty. I never really had thought of this one within my settings-library.[/quote]

Thanks for your comment. I'm also working on storing arrays as values. I'm thinking of json encoding them before storage.

As why I do a while rather than a foreach, well it's not really any different. Just the why I've always done it. The results are the same. The reason I check if it is null is simple. As far as checking for null, I could probably do away with that. Something in my mind likes to think if you call the class more than once as separate statements, then the constructor runs more than once. I'm not certain how it effects memory really. I think php takes care of that itself, but then I'm paranoid I guess.

----

@InsiteFX thanks, but it's $query->num_rows as num_rows is a property not a method. If you put the parentheses on the end like that, you'll get an error. The reason of course is that we are using the result as an object rather than processing it the old procedural method. If I were to use the procedural method, it would destroy the point of using active record and lock it into whichever database that the particular num_row method I chose to use was for. see the PHP manual --&gt; http://www.php.net/manual/en/mysqli-result.num-rows.php

As for the missing semi colon, I'm not sure what happened there, it's not missing in the source on my hdd. I must have caught it and forgot to update my clipboard before posting, that's just weird.
#5

[eluser]InsiteFX[/eluser]
CodeIgniter $query->num_rows()

The number of rows returned by the query. Note: In this example, $query is the variable that the query result object is assigned to:

So see you will not get an error! This is what causes problems when mixing and not standarizing on the coding!

#6

[eluser]Mark LaDoux[/eluser]
hah, I did not see that when I was going through the manual. My mistake, thanks for pointing that out for me. I'll change it. I went back and check the active record and saw it. I work on a lot of non-codeigniter projects, so it must have bled over. Thanks for the education!
#7

[eluser]PhilTem[/eluser]
Regarding double instantation of a library: If you load the class via the CI-loader class, then you won't have problems with doubled stuff like the items. But if you loaded the class via include and new then you better watch our for doubled items (keyword singleton). I think you can workaround with using static variables holding your setting-items because static variables only get populated once Wink
Even though I'm not quite sure if it'll help.
Therefore better load library via either $autoload['libraries'] in or $this->load->library(); so there will only be one instance of it.

Have you considered caching the config-values? I'm not quite sure if it's really sensible to do it in terms of speed with getting all results from the db vs. reading the cache-file. What do others think?^^
#8

[eluser]InsiteFX[/eluser]
@PhilTem I have to agree with you.

I use a registry type singleton with static array in my Property Class.

But I think I will add the loading and saving to a database to it.
As an option.

The CI loading can be a pain if you do not understand it. Like autoloading
a library that passes a config array through the __constructor.

@mark LaDoux those varaible variables always confused me. But if they are
over used it gets real messy in your code.
#9

[eluser]PhilTem[/eluser]
@InsiteFX Thanks Wink I started reading into the core-code recently to get a better feeling for what CI actually does. Glad I remember something from only reading^^

@mark LaDoux Have another little remark regarding the 'get()'-method: Be careful when you
[code
return FALSE;
[/code]
as a default value for items not found. It's probably safer to
Code:
return NULL;
because NULL shouldn't be falsely interpreted in terms of false-negative or false-positive values. Maybe you should also add a second parameter like
Code:
public function get($item, $return_not_found = NULL)
{
return isset($this->items[$item]) ? $this->items[$item] : $return_not_found;
}
to have possibility to define a default-value when calling 'get("my_awesome_item", "my awesome default return value");'

And be sure to keep http://www.deformedweb.co.uk/php_variable_tests.php bookmarked when doing something like an 'isset()' on values (I use it very often when I code safety-checks on a method's arguments).
#10

[eluser]Mark LaDoux[/eluser]
Thank you for your awesome comments. I'll be going over and using some of these ideas. I'll also be implementing a few new ideas of my own. I really didn't expect to get so much feedback over such a simple library.




Theme © iAndrew 2016 - Forum software by © MyBB