Today I would like to show you how I am storing and fetching the settings for my applications in CakePHP. The reason why I am doing this is pretty obvious - once the application is complete and installed it’s better to have settings such as

  • How many rows per page to show in the paginated table
  • Where is the upload dir for the files
  • What is the Date format used in the application

And many other.

Ok, without other words here is the code explanation:
The Database table is very simple:

CREATE TABLE IF NOT EXISTS `settings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key` varchar(255) NOT NULL,
  `pair` text NOT NULL,
  `description` text NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY  (`id`)
)

Key column will store the name of the setting /I am using only capital words with underscore (_) for the replacement of the spaces.
Pair is the settings value.
Description will store the human readable description of the setting as well as some explanation of the possible values.

The other 3 fields are pretty simple - ID is the primary key of the table, created and modified are the system columns where cakePHP stores the creation and last modification date.

Pair is text because this field also can store large texts like some disclaimer or some footer notes. Otherwise it should be simple varchar, but because we wont make heavy searched in that column it’s not critical :)

So, I wont stop to the UI for the settings interface. Mine was created with /console/cake script and it’s quite simple:
Add - you can fill all fields in the form,
Edit - you can change only the pair /the value/ and the description,
View - preview of the single row,
Index - showing the table with Description and pair just to indicate what we have in the settings table.
Delete - action is removed - and you know why better than me :), we don’t want some “smart” guy to decide that something is not important and to wipe it out and after this YOU are guilty and you have to search and check which setting is missing and to enter it again.

Ok, let’s imagine that we have all the UI set up and working, so how to load these things into the application so every script can see them?

Let’s create small function in the AppController class which will do the job /if you don’t have that file in you app directory, just copy it from /cake/:

<?php
class AppController extends Controller {
...
/* Function which read settings from DB and populate them in constants */
function fetchSettings(){
   //Loading model on the fly
   App::import(’Model’, ‘Setting’);
   $settings = new Setting();
   //Fetching All params
   $settings_array = $setting->findAll();
   foreach($settings_array as $key=>$value){
      $constant = "__".$value['Setting']['key'];
      $val = $value['Setting']['pair'];
      if(!defined($constant)){
         eval("define(\$constant, \$val);");
      }
   }
}
...
}
?>

What is the role of this function?
First - load the Settings model on the fly /we want to make sure that the model is loaded when we call it no matter on which Controller/. Then fetching all Settings rows in $settings_array.
After this in the loop we define all key values as name of the constant and we assign to all of them the pair value.
Because it’s not possible to define them all with deinfe($key, $value) - it’s not possible with PHP. I am creating a scring which after this I evaluate as PHP code.

That’s it, you have all your settings as constants they will look like:

define(__SHOW_ROWS_PER_PAGE, 20);

Update:
As rightly pointed, the trend in the next release of CakePHP is to move all constants in core.php to be loaded and modified with Configure class. Here is the modification which will meet this code standart:

<?php
class AppController extends Controller {
...
/* Function which read settings from DB and populate them in constants */
function fetchSettings(){
   //Loading model on the fly
   loadModel('Setting');
   $settings = new Setting();
   //Fetching All params
   $settings_array = $setting->findAll();
   foreach($settings_array as $key=>$value){
      Configure::write("__".$value['Setting']['key'], $val);
   }
}
...
}
?>

So what is the change - I am setting all variables with Configure::write() function in the configurations and after this if I need to use one of them I just need to call:

$var = Configure::read('__variable_setting');

End Update

Note the double underscore in front of each constant. They are attached in that function, I put them to make the constant unique in Cake world - so far there are only functions starting with double underscore.

Now you have just to add this function in your beforeFilter() callbacks on each controller and that’s it :) I am joking, you need to add this just in one place in the AppController class so here is the code:

<?php
class AppController extends Controller {
...
function beforeFilter(){
   $this->fetchSettings();   
   ...
}
...
function fetchSettings(){
...
}
}
?>

That’s it! Now everywhere, in controllers and helpers /all user interface logic/ you have these constants, so you can use them easily.

I will be glad to hear our opinion for this.

Tags: , , ,


Add to: del.icio.us:Storing the settings into database digg:Storing the settings into database spurl:Storing the settings into database wists:Storing the settings into database simpy:Storing the settings into database newsvine:Storing the settings into database blinklist:Storing the settings into database furl:Storing the settings into database reddit:Storing the settings into database fark:Storing the settings into database blogmarks:Storing the settings into database Y!:Storing the settings into database smarking:Storing the settings into database magnolia:Storing the settings into database segnalo:Storing the settings into database gifttagging:Storing the settings into database

11 Comments to “Storing the settings into database”

  1. Daniel HofstetterNo Gravatar | October 19th, 2007 at 12:55 pm

    Why don’t you write the values in the Configure object instead of defining constants?

  2. JadBNo Gravatar | October 19th, 2007 at 1:12 pm

    Nice overview, but like Daniel said, would be better to use the Configure::write() / read() and avoid constants.
    Another thing also, isn’t it better to make a component for the settings and instead of a findAll(), use some conditions and specific fields to return?

  3. Nik ChankovNo Gravatar | October 19th, 2007 at 1:30 pm

    Thank you, for your comments guys.

    @Daniel, I am frequent reader of your blog and I read about this from your article about “Deprecation warnings…”. It’s nice approach.

    So far it’s still not in the official release /at least the settings in core are constants.

    Anyway, this is a nice hint and I will modify the code of the example.

    Update:
    About the suggestion for Component - I think the question is reasonable, but so far I didn’t use many settings /but it’s nice tohave in the future/. About limitations: if we have limitations then it’s better to use them directly from the database, but this is not the aim I think especially when I have only 10-15 rows in that table. :)

    Thanks again.

  4. Tane PiperNo Gravatar | October 19th, 2007 at 5:36 pm

    There is actually a component for this, the ConfComponent by Othman, however I found I could only get the variables to work in views. I’ve taken it out and I’m using your technique just now, although I might end going down the Configure::write option.

    You can check out the code in action on http://dev.pastemonkey.org, as I’ve not migrated it into the live version yet.

  5. Nik ChankovNo Gravatar | October 19th, 2007 at 6:29 pm

    @Tane - thanks for your comment.

    I didn’t know about the component by Othman, but I think this one it quite simple to be used as component /if we need to be quite strict - yes but it’s 10 lines of code :)/

    About pastemonkey - very neat design. Hope it become popular in the future :)

  6. Tane PiperNo Gravatar | October 19th, 2007 at 6:48 pm

    @Nik

    Thanks.

    I’ve been playing about with things and I decided to go down the Configure::write option instead. I’ve been cutting a lot of chaff of the app today, and now have it down to six simple tables :)

    It’ll only become popular if people know about it, so please help spread the word :)

  7. fLUxNo Gravatar | November 21st, 2007 at 5:43 am

    I do this, but I also cache the settings….

    Not sure why, grabbing a few settings is trivial, but I guess I am a cache whore! xD

  8. table setting | Journal article report | January 6th, 2008 at 12:33 pm

    [...] CakePHP - Storing the settings into database [...]

  9. snowdogNo Gravatar | March 10th, 2008 at 9:40 pm

    Great article. I was just lookin for such solution. One thing - loadModel is deprecated, you should use App::import(’Model’, ‘Setting’) instead.

  10. Nik ChankovNo Gravatar | March 10th, 2008 at 9:42 pm

    @snowdog - glad that helps ;)
    About loadModel - I know, but the article was written before the function has been depricated, but it’s nice to be updated anyway. Thanks for the buzz.

  11. VeseliqNo Gravatar | July 15th, 2008 at 12:54 am

    You have omitted $val = $value['Setting']['pair']; in your brand new fetchSettings method

Leave a Comment

*
To prove that you're not a bot, enter this code
Anti-Spam Image