Part of the EllisLab Network
   
1 of 2
1
Settings Library
Posted: 01 February 2012 06:31 AM   [ Ignore ]  
Grad Student
Avatar
Rank
Total Posts:  43
Joined  09-13-2008

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

<?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() > )
        
{
            
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;
    
}
Profile
 
 
Posted: 01 February 2012 09:12 AM   [ Ignore ]   [ # 1 ]  
Lab Assistant
RankRank
Total Posts:  276
Joined  02-23-2011

Nice. Has even less lines of code than my settings-library :D

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.

 Signature 

IgnitedCo.de // Because killer robots like unicorns!

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?
Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 01 February 2012 11:10 AM   [ Ignore ]   [ # 2 ]  
Research Scientist
Avatar
RankRankRankRankRankRank
Total Posts:  5399
Joined  06-19-2009

Missing semicolon!

// 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 )  // <--- 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;
            
}
        }
    } 

 

 Signature 

Custom Designed Icons, eBook Covers Software Boxes. CD, DVD Etc. New iPhone® Tab Bar Icons and iPhone® Applications Icons.

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?

Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 02 February 2012 01:14 AM   [ Ignore ]   [ # 3 ]  
Grad Student
Avatar
Rank
Total Posts:  43
Joined  09-13-2008
PhilTem - 01 February 2012 09:12 AM

Nice. Has even less lines of code than my settings-library :D

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.

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—> 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.

Profile
 
 
Posted: 02 February 2012 02:54 AM   [ Ignore ]   [ # 4 ]  
Research Scientist
Avatar
RankRankRankRankRankRank
Total Posts:  5399
Joined  06-19-2009

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!

 Signature 

Custom Designed Icons, eBook Covers Software Boxes. CD, DVD Etc. New iPhone® Tab Bar Icons and iPhone® Applications Icons.

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?

Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 02 February 2012 04:01 AM   [ Ignore ]   [ # 5 ]  
Grad Student
Avatar
Rank
Total Posts:  43
Joined  09-13-2008

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!

Profile
 
 
Posted: 02 February 2012 04:35 AM   [ Ignore ]   [ # 6 ]  
Lab Assistant
RankRank
Total Posts:  276
Joined  02-23-2011

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?^^

 Signature 

IgnitedCo.de // Because killer robots like unicorns!

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?
Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 02 February 2012 09:33 AM   [ Ignore ]   [ # 7 ]  
Research Scientist
Avatar
RankRankRankRankRankRank
Total Posts:  5399
Joined  06-19-2009

@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.

 Signature 

Custom Designed Icons, eBook Covers Software Boxes. CD, DVD Etc. New iPhone® Tab Bar Icons and iPhone® Applications Icons.

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?

Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 02 February 2012 10:29 AM   [ Ignore ]   [ # 8 ]  
Lab Assistant
RankRank
Total Posts:  276
Joined  02-23-2011

@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;

as a default value for items not found. It’s probably safer to

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

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).

 Signature 

IgnitedCo.de // Because killer robots like unicorns!

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?
Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
Posted: 04 February 2012 01:21 AM   [ Ignore ]   [ # 9 ]  
Grad Student
Avatar
Rank
Total Posts:  43
Joined  09-13-2008

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.

Profile
 
 
Posted: 04 February 2012 01:58 AM   [ Ignore ]   [ # 10 ]  
Research Scientist
Avatar
RankRankRankRankRankRank
Total Posts:  5399
Joined  06-19-2009

For saving arrays you could just add a text field to your table and serialize and unserialize the arrays.

You can see how CodeIgniter doe’s this by looking at the CI_Session class ./system/libraries/Session.php

But json would also work.

 Signature 

Custom Designed Icons, eBook Covers Software Boxes. CD, DVD Etc. New iPhone® Tab Bar Icons and iPhone® Applications Icons.

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?

Input -> Controller | Processing -> Model | Output -> View

Profile
 
 
   
1 of 2
1