configuration

Interchange supports multiple catalogs, and therefore splits its configuration into two pieces. One is global, specified in interchange.cfg, and affects every catalog running under the same Interchange server installation. The other — catalog part, is specified in each catalog's CATROOT/catalog.cfg, and has no effect on other catalogs.

Each configuration directive is accessible on global or catalog level, or both. There's a special field named "DIRECTIVE TYPE" present in each directive's reference page, where you can look this up. Keep in mind, however, that the directives on global and catalog level don't have to be parsed by the same code — in fact, they're mostly parsed by related but different code blocks.

Configuration directives and syntax

Configuration directives are normally specified with the directive name as the first word on the line, with its value or values following. Capitalization of the directive name is not significant, but it helps readability and consistency. Additionally, any leading and trailing whitespace is removed ("stripped") before processing. Here's a simple example:

DirectiveName value

Besides specifying directive values inline, one can conveniently use the following syntax to obtain value from external files:

DirectiveName <include_filename

[Note]Note

Note that this syntax can be used anywhere on a line, such as in Variable MYSTUFF <file. You can use this to achieve the best performance with Variables.

Files included from interchange.cfg are relative to ICROOT. Files included from catalog.cfg are relative to specific catalog's CATROOT.

So-called "here document" syntax is supported as well. You can use it to spread directive values over several lines, with the usual Perl <<MARKER syntax (but unlike Perl, Interchange syntax uses no semicolon to terminate the marker). The closing marker must be the only thing on the line. No leading or trailing characters are allowed, not even whitespace. Here is a hypothetical directive using a here document:

DirectiveName <<EOD
    setting1 setting2
    setting3
EOD

The above is equivalent to:

DirectiveName setting1 setting2 setting3

Other configuration files can also be included from the current one. For example, common settings can be defined in a single file:

include common.cfg

Or all files loaded from a directory:

include usertag/*

Parsing rules

Conditional blocks

The familiar ifdef/endif and ifndef/endif pairs can be used to affect configuration processing:

Variable ORDERS_TO email_address

ifdef ORDERS_TO
  ParseVariables Yes
  MailOrderTo __ORDERS_TO__
  ParseVariables No
endif

ifdef ORDERS_TO =~ /\@foo\.com$/
  # Send all orders at foo.com to one place now
  # Set ORDERS_TO to stop default setting
  Variable  ORDERS_TO  1
  MailOrderTo   orders@foo.com
  endif

ifdef ORDERS_TO eq 'nobody@nowhere.com'
  # Better change to something else, set ORDERS_TO to stop default
  Variable  ORDERS_TO  1
  MailOrderTo   someone@somewhere.com
endif

ifndef ORDERS_TO
  #Needs to go somewhere....
  MailOrderTo  webmaster@mydomain.local
endif

Apache-like statement blocks

It is possible to define configuration directives for the duration of the block, using the <DIRECTIVE VALUE> ... </DIRECTIVE> notation:

Variable HELLO Hello World!

ParseVariables No

Message Our greeting is: __HELLO__
# Will print: Our greeting is: __HELLO__

<ParseVariables Yes>

Message Our greeting is the shiny __HELLO__
# Will print: Our greeting is the shiny Hello World!

</ParseVariables>

Message Our greeting is back to: __HELLO__
# Will print: Our greeting is back to: __HELLO__

Variables and expansion

Interchange, of course, offers a way to define variables. Variables defined in your interchange.cfg or catalog.cfg can be referenced from both configuration files themselves and the usual Interchange pages later, when the catalog is running.

Variables are defined using the Variable directive (reading its short reference now would be a good idea). The usual way to expand a variable to it's value is to use the __VARIABLE_NAME__ notation. This notation, however, is by default not enabled in RHS ("Right-Hand Side") values in configuration files. To enable it, use the ParseVariables directive which immediately affects the way Interchange parses variables in config files. Here's an example to clarify what we're talking about:

# Let's define two variables
Variable   SERVER_NAME  myhost.mydomain.local
Variable   CGI_URL      /cgi-bin/ic/tutorial

# Let's make VendURL directive be a combination of __SERVER_NAME__ and __CGI_URL__
VendURL  http://__SERVER_NAME____CGI_URL__

# To your surprise, after the above, VendURL would literally contain
# "http://__SERVER_NAME____CGI_URL__". This is not what we want, so
# we need to enable ParseVariables to achieve the desired effect:
ParseVariables Yes
VendURL  http://__SERVER_NAME____CGI_URL__
ParseVariables No

# VendURL now contains "http://myhost.mydomain.local/cgi-bin/ic/tutorial"

Subroutine watches

It may come to you as a surprise, to learn that any configuration directive can be "tied" to a Perl subroutine (if the Tie::Watch Perl module is installed). This allows for a kind of triggers, watch points, or numerous other interesting applications.

Similar to "here documents" ("<<"), subroutine watches are defined using the "<&" notation. Consider the following example:

MailOrderTo orders@myhost.mydomain.local
MailOrderTo <&EOF
sub {
	my($self, $default) = @_;
	if($Values->{special_handling}) {
		return 'vip@myhost.mydomain.local';
	}
	else {
		return $default;
	}
}
EOF

When Interchange tries to retrieve the value of the MailOrderTo configuration directive (usually to e-mail out an order), our subroutine watch is called. In turn, it returns a special value (a separate e-mail address) for customers having value "special_handling" defined in their session. For the rest, it simply returns the default value.

Now that you've grasped the basics, there's more to the story. From the above example, you see our watch subroutine was called in style of &{$subref}(SELF, PREVIOUS_VALUE). "SELF", meaning what it usually means in Perl code, is a reference to the appropriate Tie::Watch object. "PREVIOUS_VALUE" is simply the previously set value for a directive (usually its default). Those are the standard two arguments we receive in a subroutine watch if the configuration directive was of type SCALAR (defined to accept one string or text value).

[Note]Note

Subroutine watches must be defined after the configuration directives have been set to their values. Setting values after subroutine watches will simply destroy them (the watches) and have unpredictable effects.

If the configuration directive being watched was a list (type ARRAY), the subroutine would be called in pattern &{$subref}(SELF, INDEX, PREVIOUS_VALUE). ("INDEX" would be an array index of the item accessed). Setting watch points on arrays that you don't control completely is not recommended. (Namely, most Interchange subroutines call arrays in their list context, and no access method is provided for that).

Finally, if the configuration directive watched was a hash (type HASH), the subroutine would be called in pattern &{$subref}(SELF, KEY, PREVIOUS_VALUE). ("KEY" would be a name of the hash value accessed). In the following example, we tie the Variable configuration directive. This is not recommended for performance reasons — Variable directive is called very often and should not bear any extra overhead). But it illustrates the power of this operation:

Variable TESTIT Unwatch worked.

Variable <&EOV
sub {
  my ($self, $key, $orig) = @_;

  if($key eq 'TESTIT') {
    # only the first time
    if($Scratch->{$key}++) {
      $self->Unwatch();
      return $orig->{TESTIT};
    }
    else {
      return "Tie::Watch works! -- name=$Values->{fname}";
    }
  }
  else {
    return $orig->{$key};
  }
}
EOV

The first time __TESTIT__ is called for an individual user, it would return the string "Tie::Watch works! -- name=NAME" along with their first name (if they provided one at some point). On a second access (again, for an individual user), the watch would be dynamically dropped and the default value of the variable TESTIT returned. All other variables would operate as usual.

DocBook! Interchange!