Simple and Slick Configuration Manager in Miva Script
Saving configuration settings in your Miva Script apps is necessary but very easy.
Use the time saving mivascript functions below to create a flexible configuration system for your Miva Script apps that can easily grow as your app grows with minimal coding.
by Scot Ranney
Configuration data in your Miva Script apps is a fact of life, along with the fact that as your app grows you will need to add new configuration settings. Knowing how to extend your configuration data quickly and easily is key.
Configuration data takes many forms and is often put in a table or database, however the problem is that every time you add a new configuration field, you have to update the database. That's why I like to use flat files for my configuration fields. It's easy to update and add to, and as we all know, the more customizable an app is, the easier it is to please more customers which means more sales.
Here are my four configuration routine functions.
get_fields()
The get_fields() function returns a list of configuration fields my Miva Script app uses. When I want to add a new configuration field, I just add it to the list. In this example, I have an admin username and admin password field.
<MvFUNCTION NAME = "get_fields" PARAMETERS = "" STANDARDOUTPUTLEVEL=""> <MvFUNCRETURN VALUE ="{' g.config_admin_username, g.config_admin_password '}" </MvFUNCTION>
config()
The config() function is called at the beginning of the Miva Script app to set all the global variables. If the config file is not found, it creates the initial config file.
<MvFUNCTION NAME = "config" PARAMETERS = "" STANDARDOUTPUTLEVEL = ""> <MvCOMMENT> ** this hard codes your data directory name ** </MvCOMMENT> <MvASSIGN NAME = "g.data" VALUE = "{ 'appdata' }"> <MvCOMMENT> ** this creates the data directory if it doesn't exist ** </MvCOMMENT> <MvIF EXPR = "{NOT fexists(g.data)}"> <MvASSIGN NAME = "l.ok" VALUE = "{ fmkdir(g.data) }"> </MvIF> <MvCOMMENT> ** if the config file exists, read it, if not, initialize it with preset values** </MvCOMMENT> <MvIF EXPR = "{fexists(g.data $ '/config.dat')}"> <MvIMPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{ asciichar(165) }"> </MvIMPORT> <MvFUNCRETURN VALUE = "{ 1 }"> <MvELSE> <MvASSIGN NAME = "g.config_admin_username" VALUE = "{ 'admin' }"> <MvASSIGN NAME = "g.config_admin_password" VALUE = "{ 'my_password' }"> <MvEXPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{asciichar(165)}"> </MvIF> </MvFUNCTION>
edit_config()
The edit_config() function is where the administrator of the script changes configuration options. Each time you add a customizable config variable, you will need to add it to this form. Each configuration field that is editable needs to be added to this config form.
<MvFUNCTION NAME = "edit_config" PARAMETERS = "" STANDARDOUTPUTLEVEL="compresswhitespace,html,text"> <form method="post" action="{ s.documenturl $ 'edit_config2' }"> <p> Admin login: <input type="text" name="_config_admin_username" value="{ g.config_admin_username }"> </p> <p> Admin password: <input type="text" name="_config_admin_password" value="{ g.config_admin_password }"> </p> <p> <input type="submit" value="save changes"> </p> </form> </MvFUNCTION>
edit_config2()
The edit_config2() function updates the configuration file. I used the built-in miva_variable_value(..)
function to go through and set the list of fields in the get_fields() function, then I write the new config file after deleting the old one first.
<MvFUNCTION NAME = "edit_config2" PARAMETERS = "" STANDARDOUTPUTLEVEL=""> <MvCOMMENT> ** set the config variables first so we know where the data directory is (probably redundant since the config() function is usually called at the very beginning of the script anyway) ** </MvCOMMENT> <MvASSIGN NAME = "l.ok" VALUE = "{ config() }"> <MvCOMMENT> ** delete the existing config file ** </MvCOMMENT> <MvIF EXPR = "{fexists(g.data $ '/config.dat')}"> <MvASSIGN NAME = "l.ok" VALUE = "{ fdelete(g.ssf_data $ '/config.dat') }"> </MvIF> <MvASSIGN NAME = "l.pos" VALUE = "{ 1 }"> <MvASSIGN NAME = "l.fields" VALUE = "{ get_fields() }"> <MvCOMMENT> ** this sets the new global variables ** </MvCOMMENT> <MvWHILE EXPR = "{ gettoken(l.fields,',',l.pos) }"> <MvASSIGN NAME = "l.var" VALUE = "{ trim(gettoken(l.fields,',',l.pos)) }"> <MvASSIGN NAME = "l._var" VALUE = "{ glosub(l.var,'g.','g._') }"> <MvASSIGN NAME = "{ l.var }" VALUE = "{ miva_variable_value(l._var) }"> <MvASSIGN NAME = "l.pos" VALUE = "{ l.pos+ 1 }"> </MvWHILE> <MvCOMMENT> ** export the new configuration file ** </MvCOMMENT> <MvEXPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{asciichar(165)}"> </MvFUNCTION>
How does it work in your Miva Script App?
1. Add the functions to your Miva Script app or module.
2. At or near the top of your Miva Script app, call the config() function to set your configuration variables:
<MvASSIGN NAME = "l.ok" VALUE = "{ config() }">
If your Miva Script app handles uploads, you'll also need to call the config() in the Miva_ProcessFileUpload(..)
and Miva_ValidateFileUpload(..)
functions because everything else is bypassed during an upload.
3. Add a link to edit the config file that sends an action variable used to call the edit_config() function.
4. Add calls for the edit_config() and edit_config2() functions.
Sample Miva Script Config Test App
<MvCOMMENT> |-------------------------------- | Simple Miva Script App with Configuration | | 1. Call the config at the top of the script | 2. Check the actions - if editing or updating the config | 3. Run the main() function (the main part of the app - "Hello World") |-------------------------------- </MvCOMMENT> <MvASSIGN NAME = "l.ok" VALUE = "{ config() }"> <MvIF EXPR = "{g.action EQ 'edit_config2'}"> <MvASSIGN NAME = "l.ok" VALUE = "{ edit_config2() }"> </MvIF> <MvIF EXPR = "{g.action EQ 'edit_config'}"> <MvASSIGN NAME = "l.ok" VALUE = "{ edit_config() }"> </MvIF> <MvASSIGN NAME = "l.ok" VALUE = "{ main() }"> <MvEXIT> <MvCOMMENT> |-------------------------------- | main function |-------------------------------- </MvCOMMENT> <MvFUNCTION NAME = "main" PARAMETERS = "" STANDARDOUTPUTLEVEL="compresswhitespace,html,text"> <p> Hello World! </p> <p> <a href="{ s.documenturl $ 'action=edit_config' }">Click Here</a> to edit the configuration. </p> </MvFUNCTION> <MvCOMMENT> |-------------------------------- | configuration functions |-------------------------------- </MvCOMMENT> <MvFUNCTION NAME = "get_fields" PARAMETERS = "" STANDARDOUTPUTLEVEL=""> <MvFUNCRETURN VALUE ="{' g.config_admin_username, g.config_admin_password '}"> </MvFUNCTION> <MvFUNCTION NAME = "config" PARAMETERS = "" STANDARDOUTPUTLEVEL = ""> <MvCOMMENT> ** this hard codes your data directory name ** </MvCOMMENT> <MvASSIGN NAME = "g.data" VALUE = "{ 'appdata' }"> <MvCOMMENT> ** this creates the data directory if it doesn't exist ** </MvCOMMENT> <MvIF EXPR = "{NOT fexists(g.data)}"> <MvASSIGN NAME = "l.ok" VALUE = "{ fmkdir(g.data) }"> </MvIF> <MvCOMMENT> ** if the config file exists, read it, if not, initialize it with preset values** </MvCOMMENT> <MvIF EXPR = "{fexists(g.data $ '/config.dat')}"> <MvIMPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{ asciichar(165) }"> </MvIMPORT> <MvFUNCRETURN VALUE = "{ 1 }"> <MvELSE> <MvASSIGN NAME = "g.config_admin_username" VALUE = "{ 'admin' }"> <MvASSIGN NAME = "g.config_admin_password" VALUE = "{ 'my_password' }"> <MvEXPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{asciichar(165)}"> </MvIF> </MvFUNCTION> <MvFUNCTION NAME = "edit_config" PARAMETERS = "" STANDARDOUTPUTLEVEL="compresswhitespace,html,text"> <form method="post" action="{ s.documenturl $ 'action=edit_config2' }"> <p> Admin login: <input type="text" name="_config_admin_username" value="{ g.config_admin_username }"> </p> <p> Admin password: <input type="text" name="_config_admin_password" value="{ g.config_admin_password }"> </p> <p> <input type="submit" value="save changes"> </p> </form> </MvFUNCTION> <MvFUNCTION NAME = "edit_config2" PARAMETERS = "" STANDARDOUTPUTLEVEL=""> <MvCOMMENT> ** set the config variables first so we know where the data directory is (probably redundant since the config() function is usually called at the very beginning of the script anyway) ** </MvCOMMENT> <MvASSIGN NAME = "l.ok" VALUE = "{ config() }"> <MvCOMMENT> ** delete the existing config file ** </MvCOMMENT> <MvIF EXPR = "{fexists(g.data $ '/config.dat')}"> <MvASSIGN NAME = "l.ok" VALUE = "{ fdelete(g.ssf_data $ '/config.dat') }"> </MvIF> <MvASSIGN NAME = "l.pos" VALUE = "{ 1 }"> <MvASSIGN NAME = "l.fields" VALUE = "{ get_fields() }"> <MvCOMMENT> ** this sets the new global variables ** </MvCOMMENT> <MvWHILE EXPR = "{ gettoken(l.fields,',',l.pos) }"> <MvASSIGN NAME = "l.var" VALUE = "{ trim(gettoken(l.fields,',',l.pos)) }"> <MvASSIGN NAME = "l._var" VALUE = "{ glosub(l.var,'g.','g._') }"> <MvASSIGN NAME = "{ l.var }" VALUE = "{ miva_variable_value(l._var) }"> <MvASSIGN NAME = "l.pos" VALUE = "{ l.pos+ 1 }"> </MvWHILE> <MvCOMMENT> ** export the new configuration file ** </MvCOMMENT> <MvEXPORT FILE = "{g.data $ '/config.dat'}" FIELDS = "{ get_fields() }" DELIMITER = "{asciichar(165)}"> <MvEVAL EXPR = "{'<p >Configuration file updated!</p>'}"> </MvFUNCTION>
Related Articles
These articles might be interesting for you as well: