WDB - New Features ------------------ Bo Frese Rasmussen 2-Jul-1997 This is some notes on the new features in WDB since the last public release. ##### # There are still a couple of things that I'd like to add/fix in this version # of WDB, but haven't had the time to. I've included some comments about this # where appropriate (marked with '####' like this paragraph). PATH_INFO --------- The URL to call WDB has changed to a more generic form. http://.../cgi-bin/wdb//=/=/... The /cgi-bin/wdb/, can of course be any path, depending on where WDB is installed. If a different name than 'wdb' is used for the script, another configuration file will be loaded. This can be used when several applications on the same server are using WDB, but they all need different configuration. (See the section on installation and configuration later) The is the action to take. ( form/query/delete/update/... ). The = pairs are definitions of various parameters needed by the particular action. These parameters can also be send as FORM fields if needed (use field name= wdb_). Some of the common parameters are: fdf Defines the form definition file to use. ldf Defines the layout to use. THE LAYOUT DEFINITION FILES (LDF files) --------------------------------------- All HTML output from WDB is now controlled by LDF files. For each FDF file there should be a LDF file which defines the various layouts for query-forms, query-results, etc.. This also controls how the different forms call each other. Support for some persistence of query info, etc. has also been added. The syntax of the LDF file is, much like the FDF file, a set of keywords followed be '=', and a value. The keywords are names of layouts, and the values are the HTML to use. Lines beginning with one or more blanks are continuations of the previous line. Lines beginning with '#' are comments. WDB is using a set of extra HTML-like tags to define WDB specific behavior and layout. All of these extra tags has the form : This is case sensitive, and all tag-names and parameter names are upper-case, and all values are enclosed by quotes. WDB parameters can be embedded inside other HTML tags (f.ex inside a or a
), but WDB tags can't have other tags (WDB or HTML) embedded inside them. The following lists all the WDB tags, and their parameters: ----- Defines the start and end of the row definition. This is the part of the layout that repeats for each returned row in a query. NONE= The name of the layout to insert in this place if now rows are returned from the query. # Maybe an option for replacing the entire layout with # another should be added. ----- Includes another layout. LAYOUT= Name of another layout in the same LDF file to include SRC= Name of a file to include. ----- Inserts the value of a given field in the output. NAME= Name of the field (as given in the FDF file 'FIELD=') TYPE= Type of output to produce. Currently the following are supported : query - A HTML-FORM query field (for input) text - Formated HTML text (for output) update - A HTML-FORM field for update/insert of values hidden - A hidden field. escaped - A CGI encoded version of the field value label - The field label. unit - The field units. errormsg - The HTML formated error-message for the field. ----- This outputs the value of the given parameter. NAME= The name of the parameter Parameters are those special values typically pased in the PATH_INFO part of the URL to WDB. For example in 'http://www/cgi-bin/wdb/query/fdf=myfdf/mypar=myval' the values of 'fdf' and 'mypar' can be referenced with and . Parameters can also be pased as fields in a form, but then the field name have to be 'wdb_' + the name of the parameter. ----- This outputs the value of the given variable. NAME= The name of the variable. Variables can be either variables set in the wdb.conf configuration file, or variables set in one of the evaluated attributes in the FDF. F.ex. the PERL attribute ----- This tag is used in place of a URL, to call WDB with a given action. NAME= Name of the action to take (required) FDF= FDF to use (Optional - Default = current) LDF= LDF to use (Optional - Default given by action) KEYS (Optional - Include unique keys to current row) QUERY (Optional - Include all attributes of current query) KEEP= A comma (,) separated list of wdb parameters to keep from this invocation of WDB. Each parameter can optionally have a '=' appended, where is the name of a field from the current FDF. This will copy the current value of this field to the parameter. - I guess this really needs an example.... Suppose you want your users to identify themselves with a user-name, that you later want to refer to. You call WDB with something like this http://.../cgi-bin/wdb/form/fdf=tst/ldf=login Your LDF file could look a bit like this. -------- login= .... "> User name: "> -------- Now suppose you wanted to present a list of possible user-names from a database table and allow the user to simply select one. (The LDF FIELD name is 'USER') -------- select_user= .... "> - Login as
... -------- ----- The NEXT tag generates a link in HTML to display the next records in the current query. It produces a self referencing link, which includes the values of the current query, plus a special wdb parameter called 'start' which tells WDB how many rows of the query to skip first. (Usually used in connection with and ) ROWS= Number of rows to go forward. IMG= Image to use as anchor. (Optional) TXT= Text to use as anchor. (Optional) At least on of the IMG or TXT attributes should be specified. ----- The PREV tag generates a link in HTML to display the previous records in the current query. (Usually used in connection with and ) ROWS= Number of rows to go back. IMG= Image to use as anchor. (Optional) TXT= Text to use as anchor. (Optional) At least on of the IMG or TXT attributes should be specified. ----- This sets various HTTP options. HEADER= HTTP header (Default is "Content-type: text/html\n\n") This can be used to send f.ex. redirects, access denied, and other HTTP headers. ##### # In the case of redirects it would be really nice to be able to use # as part of the header. Unfortunately WDB tags can't be # nested inside each other... BUILD-IN ACTIONS ---------------- form Simply generate the HTML, typically a search form (default ldf=query) query Queries the database using the form input. The generates HTML output, repeating the part of the LDF for each row returned. (default ldf=tab) ins_form Simply generate the HTML, typically a form for inserting new data. (default ldf=ins_form) ##### # This is actually exactly the same as 'form'.... # - originally I must have had some ideas abut things # that it should do differently... insert Verifies the form input, and inserts the row in the database. If there are errors in the input the ins_form ldf is displayed again, with form fields filled out with the previous input, and error messages displayed. (remember to include 'error' fields in the ins_form ldf.) (default ldf=insert) ####### # At the moment the ldf name of the insert form to show # again on error is hard-coded to 'ins_form'. - not # very clever .... :-) upd_form Displays a form for updating a record. This should be called with the parameter 'keys' that uniquely identifies a row. (default ldf=upd_form) update Like 'insert', it verifies the input and updates the row or redisplays the 'upd_form' with error messages. (default ldf=update) delete Deletes the row. This should be called with the parameter 'keys' that uniquely identifies a row. ############### # The two actions : release and del_released that currently are included # in the distributions should actually be removed. They where specifically # developed for a project called DARWIN. What needs to be done in WDB # is an easy way to put project specific actions in a project specific # directory, f.ex. together with the fdf's THE DATABASE INTERFACE (DBI) ---------------------------- The database interface is now using a base class, called DBI, which defines the basic database operations (connect, open query, get next row, close query, etc.), and a set of high level operations that are more tightly linked to WDB. In order to support a specific database systems, a sub class of DBI should be written, which implements the basic database operations. It is usually not necessary to implement specific versions of the high level operations, unless the database is using a very non-standard version of SQL (or maybe a completely different query language). ...More documentation should probably be written about this, but for now look in the comments in WDB/DBI.pm and WDB/DBI_Oracle.pm EVALUATED EXPRESSIONS IN CONFIGURATION FILES ------------------------------------------- Just like in the old WDB, some of the FDF attributes are evaluated using perl 'eval'. (f.ex. to_db, from_db, PERL, etc.). However some of the variables available in the eval's has changed a bit. %form : Assoc. array of the FDF form attributes. %field : Assoc. array of the FDF field attributes. These are accessed like this $val = $field{FIELD,attribute} Where FIELD is the name of the field (Given by FIELD= in the FDF) and attribute is on of the attributes of the field. There are also a set of special attributes available : value : The current value of the field. query : The current query value of the field oper : The current query operand on the field Also a set of variables are extracted from the HTTP header : $REMOTE_HOST $REMOTE_USER $SERVER_NAME $SERVER_PORT $HTTP_USER_AGENT $HTTP_HOST And the following is extracted from $HTTP_USER_AGENT $BROWSER $BROWSER_VER ERROR HANDLING -------------- Because WDB now allows you to change the HTTP header, this is output a bit later than before. This means that error messages are not always simply printed to std.out (the browser) as before. However WDB now as some new configuration options to redirect error output to an email address, to a file, or to stdout/stderr. #--------------------------------------------- require 'Error'; &Error::Logfile( 'filename' ); &Error::Email( 'email@host.dk' ); &Error::NoStdout(); # Disables terminal output #--------------------------------------------- INSTALLATION AND CONFIGURATION ------------------------------ I usually un-tar WDB in the SERVER_ROOT directory (creating a sub-dir called wdb), and then make appropriate symbolic links for each application that needs WDB. For example my phonebook project is then installed like this : I create a sub-dir in SERVER_ROOT called 'phone' where I put all the project specific files. The phone book FDF and LDF files are then placed in $SERVER_ROOT/phone/fdf/. All this is of course checked in under CVS, making it easy to have a development server, and then 'update' the production system when everything is properly tested. In /cgi-bin/ I make a symbolic link called 'phone' that point to $SERVER_ROOT/wdb/wdb. This means that WDB would be accessed through the URL http://..../cgi-bin/phone/... - this makes WDB first look for a configuration file called 'phone.conf', before it looks for the default 'wdb.conf'. - So I copy the wdb.conf.template file to phone.conf and edit it to suit my phonebook project. NOTE: An important 'trick' here is to use a 'symbolic' link (ln -s) from cgi-bin to wdb. WDB automatically follows this symbolic link to find out where it is installed, and looks for configuration files in the same directory. This makes it easier to upgrade WDB, as there is no need to edit any of the WDB files. Simply un-tar the new version on top of the old. I do this on a running system - and nobody has ever complained ... :-) THE CODE -------- Most of the code has been completely restructured. It's now using a more object oriented design. The goal of this exercise was among others, to make it easier to extend WDB with support for new functions, databases, etc. without touching the core code. One of the problems with the old WDB was that it was difficult to incorporate extensions contributed by others. The idea was to introduce something like 'plug-ins', that would make it very easy to add new modules. Now all the 'actions' (like 'form', 'query', 'insert', 'update', 'delete', etc.) are auto-loaded from a directory called 'auto'. All it takes to add a new 'action' is to write the module and put it in the auto directory, and call WDB with a URL that references the name of the action. Also new field types can be added by simply adding a module called Field_.pm, inheriting from the base type, and just add the extra features, f.ex. stricter verification, special conversion, etc. If you are planing to add features to WDB please think about a way to add them in a new module, and not touch the existing ones. If this can not be done, please think of a way to change WDB to allow your kind of extension to be added with out changing WDB... - I know I haven't been entirely consistent in doing this myself, but thats the way the code is heading... - And it's really the only way to keep up with updates, etc.. Lot's of people has sent me updates to the old WDB, but it was almost impossible to merge the changes together, so very few of them ever made into the standard WDB distribution. So please think of ways to add it as 'plug-ins', auto-loaded modules, etc. Also, I'm using this version of WDB in three production systems, so I'm unlikely to make changes that are not backwards compatible with this version. (-thats not a guarantee though) ######## # This should be extended with the possibility to load 'actions' from # other 'application' specific directories, f.ex. from the FDF directory. ####################### # IDEAS FOR IMPROVEMENT ####################### # If would be really nice with an even more generic kind of LDF file. Sort of a 'style sheet', which would specify the general way to present a query form, a query result, and insert form, etc. for any FDF. In this way it would be just as quick to get up and running as with the old WDB, where you just had to produce the FDF file (which for some databases could be generated automatically). A default style sheet could be provided that looked like the old WDB output, and in this way make porting of applications from the old WDB to the new WDB really easy... These style sheets, could be produced either on-the-fly or - more efficiently - from a command-line tool that given a FDF (and a style sheet), produces a LDF. # #####################