Simply storing config values in the DB

This article is also available in the following languages:
By iamcam
There are many situations in web apps where site-wide configurations need to be accessible to users through admin interfaces, rather than configuration files residing on the server. It is a practical method of storing configuration values that may need changing from time to time, but without access to the core configuration file.

Code

Settings are stored in the database, so we will first need to start by creating the table:
CREATE TABLE `settings` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `key` varchar(48) NOT NULL,
  `value` text,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `key` (`key`)
)

Next, go ahead and bake your model and controller, but don't worry about baking-in some of the pre-built methods. Modify your model to look like this:

Model Class:

<?php 
class Setting extends AppModel {

    var 
$name 'Setting';
    var 
$key 'MyApp';
    
    
//retrieve configuration data from the DB
    
function getcfg(){
            
$key=$this->key;
            
$cfgs $this->find('first',array('fields'=>array('id','key','value')));

            if (
count($cfgs)) {
                
$this->checksum=$cfgs['Setting']['value'];
                
$cfgVal unserialize($cfgs['Setting']['value']);

            }
            
Configure::write($key,$cfgVal);
    }

    
//write configuration data back to the DB
    
function writecfg(){
        
$key $this->key;

        
$rev Configure::read($key);

        
$value=serialize($rev);
        
        
//if the configs haven't changed, no need to save them
        
if ($value==$this->checksum) return;
        
        
//otherwise the configs have changed, so 

        
$this->data = array('key'=>$key,'value'=>$value);

        if (
$setting $this->findByKey($key)) {
            
$this->data['id'] = $setting['Setting']['id'];
        }

        
$this->save($this->data);
    }
}
?>
You'll notice that Configure:: values are serialized and stored together using the MyApp Configure::key. At first this may seem somewhat counter intuitive to how we think we should store configurations. However, consider the hassle involved with trying to figure out how/where to store multi-dimensional arrays in an inherently flat storage system (db). It's probably doable, but not without considerable headaches. Storing everything in a serialized string allows Cake to worry about creating the structure - we just save the output.

Next, open up your app_controller.php file and add the following code to the top of the class:
var $uses = array('Setting');
You will also need to add some code to your AppController beforeFilter() and afterFilter() methods:

Controller Class:

<?php 
class AppController extends Controller {

     var 
$uses = array('Setting');

     function 
beforeFilter(){
         
//reads the site-wide config values from the DB and puts them through the Configure::write method
         
$this->Setting->getcfg();
     }

     function 
afterFilter(){
         
//retrieves the site-wide configurations from Configure::read($key) and puts it back into the db if new
         
$this->Setting->writecfg();
     }
}
?>

Usage

Any place you would like to store a Configure:: value in the database, you only need to use the $key specified in the model. If you don't, the values will not get saved. An example would look something like:
<? Configure::write('MyApp.themeName','My Great Theme'); ?>
Since the retrieval code is run in the before filter, we can treat the Configure:: vars like any others in our app when we need to access them. To recall a value we would run something like:
<? $myVar = Configure::read('MyApp.themeName'); //returns 'My Great Theme' ?>

Next Steps

Because this is only a very simple way to store configuration data (one row for the entire app), there will likely be some desire to extend it. You may wish to segregate certain data into their own rows (perhaps individual plugins or components), which would only require some additional code to accept additional keys for read/write access. That, my friends, is a job for another tutorial.

Comments

  • Posted 01/08/09 08:09:48 PM
    I'm not quite sure what is occurring; it seems this issue may be more related to the CakePHP Configure class than this actual tutorial. Copying script verbatim, I notice my SQL queries do have the appropriate syntax. However, when I view the table through PHPMyAdmin, the value is "N;" (without quotes). I figured perhaps the tutorial kept writing the value somehow so I went into the Model and stopped execution at several different points; every time the SQL log showed the proper query being executed (proper values are being inserted). I have even refreshed PHPMyAdmin a few times for it to reflect the proper values. But somehow between the execution of 'writecfg' and the final display the value is changed to 'N;'. I'm not sure why but I'm Googling and hope to find an answer (and post resolution) soon.

    Using CakePHP 1.2.0.7962 Final

    (Issue posted in Google Groups http://groups.google.com/group/cake-php/browse_thread/thread/6cd8f73a440d0d7b?hl=en)
  • Posted 11/03/08 02:11:07 PM
    The comments are appreciated.
    @Jonah Turnquist: You're right - a flat file would just as well. Cake has a method to define a flat file used to store your configuration files. Either way should work fine.

    @Christian Deluxe: That's definitely in the direction of another idea/method I had for storing values.

    Perhaps one benefit to storing any config values in a database is that you can apply scope to the data being selected. Consider the situation in which you have several sites (subdomains?) running off of one set of Cake files and one database. Applying the scope of "mysite" to your select statement can be an easy way to segregate settings used on different web sites.
  • Posted 10/30/08 04:53:34 PM
    Hi, here my changes for save one row for each setting, it allow to modify, create and delete directly from views, so users can modify all values.

    The function writecfg() is not needed but i changed too for if you want to use it

    Model Class:

    <?php 
    class Setting extends AppModel {

        var 
    $name 'Setting';
        var 
    $key 'MyApp';
        var 
    $custom_settings = array();

        
    //retrieve configuration data from the DB
        
    function getcfg(){
            
    // get all settings from db
            
    $cfgs $this->find('all', array('fields'=>array('id','key','value')));

            
    // if not is array we exit
            
    if( !is_array($cfgs) ) return;

            
    // parse each setting
            
    foreach($cfgs as $cfg) {

                
    // build the array for use later
                
    $data_array = array(
                            
    'id' =>    $cfg['Setting']['id'],
                            
    'key' => $cfg['Setting']['key'],
                            
    'value' => $cfg['Setting']['value'],
                            
    'checksum' => md5($cfg['Setting']['value']) );
                
    $this->custom_settings[] = $data_array;

                
    // write the config
                
    Configure::write($this->key '.' $cfg['Setting']['key'], $cfg['Setting']['value']);
            }
        }

        
    // actually don't needed, you can modify values in db directly
        //write configuration data back to the DB
        
    function writecfg(){
            
    // read each setting from the array
            
    foreach($this->custom_settings as $cfg) {
                
    $new_value Configure::read($this->key '.' $cfg['key']);

                
    // if the setting have changed
                
    if( md5($new_value) !=  $cfg['checksum']) {
                    
    // make sql
                    
    $this->data = array(
                                
    'id'=> $cfg['id'],
                                
    'key'=> $cfg['key'],
                                
    'value'=> $new_value);
                    
    // save it
                    
    $this->save($this->data);
                }
            }
        }
    }
    ?>

    Sorry for my bad English.

    Best regards
  • Posted 10/27/08 01:28:37 PM
    Since all the config values being serialized and stored in a single cell in a mysql table, why not just store the serialize config values in a flat file instead? This may be faster and also some apps might not use a database. Plus it's simpler.
  • Posted 10/27/08 06:52:04 AM
    This is almost similar to my implementation:

    http://dsi.vozibrale.com/articles/view/simple-db-based-configuration-for-cakephp-apps
    Almost :)

Comments are closed for articles over a year old