Interchange Documentation (Full)


This is the documentation for Interchange, all in one large file.

Interchange Advanced Topics
Interchange Catalog-Building Tutorial
Interchange Configuration
Interchange Database
Interchange Ecommerce Functions
Interchange Foundation Store
Interchange I18N Features
Interchange Templates
Interchange Tags Reference
Interchange Frequently Asked Questions
Interchange Upgrade Guide
Interchange Programmer Variables Reference

line:

Interchange Ecommerce Functions

1. THE ORDER PROCESS

Interchange has a completely flexible order basket and checkout scheme. The foundation demo presents a common use of this process, in the directory pages/ord -- the files are:

    basket.html      The order basket displayed by default
    checkout.html    The form where the customer enters their billing
                     and shipping info
    receipt.html     The receipt displayed to the customer
    report           The order report mailed to you
    mail_receipt     The customer's email copy (if requested)

It is not strictly necessary to display an order basket when an item is ordered. If you specify a different page to be displayed that is fine, but most customers will be confused if you don't give them an indication that the order operation has succeeded.

Any order basket is an HTML FORM. It will have a number of variables on it. At the minimum it must have an [item-list] to loop through the items, and the quantity of each item must be set in some place on that form. Any valid Interchange tags may be used on the page, and you may use multiple item lists if necessary.

1.1. How to order an item

Interchange can either use a form-based order or a link-based order to place an item in the shopping cart. The link-based order uses the special [order item-code] tag:

[order code]

            [order code="sku" quantity="n"* href="page"* cart="cartname"* base="table"*]
            * = optional parameters
      Order a [order TK112]Toaster</a> today.
      Order a [page order TK112]Toaster</A> today.
      Order a <A HREF="[area order TK112]" TARGET=newframe>Toaster</A> today.

[/order]

To order with a form, you set the form variable mv_order_item to the item-code/SKU and use the refresh action:

  <FORM ACTION="[process-target]" METHOD=POST>
  <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">
  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK112">

  Order <INPUT NAME="mv_order_quantity" SIZE=3 VALUE=1> toaster

  <INPUT TYPE=submit VALUE="Order!">
  </FORM>

You may batch select whole groups of items:

  <FORM ACTION="[process-target]" METHOD=POST>
  <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">

  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK112">
  <INPUT NAME="mv_order_quantity" SIZE=3> Standard Toaster

  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK200">
  <INPUT NAME="mv_order_quantity" SIZE=3> Super Toaster

  <INPUT TYPE=submit VALUE="Order!">
  </FORM>

Items that have a quantity of zero (or blank) will be skipped, and only items with a positive quantity will be placed in the basket.

You may also specify attributes like size or color at time of order (see How to set up an order button).

1.2. How to set up an order link

On a product display page, use:

    [order 00-0011]Order the Mona Lisa</a>

If coming from a search results or on-the-fly page, you may use the generated [item-code] thusly:

    [order [item-code]]Order [item-field name]</a>

Bear in mind that if you have not reached the page via a search or on-the-fly operation, [item-code] means nothing and will cause an error.

1.3. How to set up an order button

Interchange can order via form submission as well. This allows you to order a product (or group of products) via a form button. In its simplest form, it is:

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa">
    </FORM>

The default quantity is one. An initial quantity may be set by the user by adding an mv_order_quantity variable:

     Number to order:<INPUT TYPE=text NAME=mv_order_quantity VALUE="1">

You can order multiple items by stacking the variables:

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
    </FORM>

Initial size or color may be set as well, provided UseModifier is set up properly:

    <INPUT TYPE=hidden NAME=mv_order_size VALUE="L">

If the order is coming from a generated flypage, loop list, or search results page, you can get a canned select box from the [item-accessories size] or [item-accessories size] tag. See Item Attributes.

1.4. How to set up an on-the-fly item

If you enable the catalog directive OnFly, setting it to the name of a subroutine (or possibly a UserTag) that can handle its calls, then Interchange will add items to the basket that are not in the product database. Interchange supplies an internal onfly subroutine, which will work according to the examples given below.

In catalog.cfg:

    OnFly  onfly

If your item code is not to be named mv_order_item then you must perform a rename in the Autoload routine.

A basic link can be generated like:

    <a href="[area form="
            mv_todo=refresh
            mv_order_item=000101
            mv_order_fly=description=An on-the-fly item|price=100.01
    "]">Order item 000101</a>

The form parameter value mv_order_fly can contain any number of fields which will set corresponding parameters in the item attributes. The fields are separated by the pipe (|) character and contain value-parameter pairs separated by an = sign. (These are URL-encoded by the [area ...] or [page ...] tag, of course.) You can set a size, color, or any other parameter.

The special attribute mv_price can be used in conjunction with the CommonAdjust atom $ to set the price for checkout and display.

The [item-list] sub-tag [item-description], when used with an item-list, will use the item attribute description to display in the basket. Note that [item-field description] or [item-data products description] will NOT work, as both of these tags reference an actual field value for a record in the products table - not applicable for on-the-fly items. Similarly, an attempt to generate a flypage for an on-the-fly item ([page 000101], for example) will fail, resulting in the display of the SpecialPage missing.

If you wish to set up a UserTag to process on-the-fly items, it should accept a call of

    usertag(mv_item_code, mv_item_quantity, mv_order_fly)

The mv_item_code and mv_order_fly parameters are required to trigger Interchange's add_item routine (along with mv_todo=refresh to set the action).

The item will always act as if SeparateItems or mv_separate_items is set.

Multiple items can be ordered at once by stacking the variables. If there is only one mv_order_item instance, however, you can stack the mv_order_fly variable so that all are concatenated together as with the | symbol. So the above example could be done as:

    [area form="
            mv_todo=refresh
            mv_order_item=000101
            mv_order_fly=description=An on-the-fly item
            mv_order_fly=price=100.00
    "]

Multiple items would need multiple instances of mv_order_item with a corresponding mv_order_fly for each mv_order_item. You can order both 000101 and 000101 as follows:

    [area form="
        mv_todo=refresh

        mv_order_item=000101
        mv_order_fly=description=An on-the-fly item|price=100.00

        mv_order_item=000102
        mv_order_fly=description=Another on-the-fly item|price=200.00
    "]

The following two forms correspond to the above two examples, in order, with the slight refinement of adding a quantity:

  <FORM ACTION="[area process]" METHOD=POST>
        <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1">
        <INPUT TYPE=hidden NAME=mv_order_fly
                VALUE="description=An on-the-fly item|price=100.00">
        <INPUT TYPE=submit VALUE="Order button">
    </FORM>

   <FORM ACTION="[area process]" METHOD=POST>
        <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
        <INPUT TYPE=hidden NAME=mv_order_fly
            VALUE="description=An on-the-fly item|price=100.00">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000102">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
        <INPUT TYPE=hidden NAME=mv_order_fly
            VALUE="description=Another on-the-fly item|price=200.00">
        <INPUT TYPE=submit VALUE="Order two different with a button">
    </FORM>

1.5. Order Groups

Interchange allows you to group items together, making a master item and sub-items. This can be used to delete accessories or options when the master item is deleted. In its simplest form, you order just one master item and all subsequent items are sub-items.

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
    </FORM>

If you wish to stack more than one master item, then you must define mv_order_group for all items, with either a 1 value (master) or 0 value (sub-item). A master owns all subsequent sub-items until the next master is defined.

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="19-202">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="99-102">
    <INPUT TYPE=submit VALUE="Order items">
    </FORM>

When the master item 00-0011 is deleted from the basket, 00-0011a will be deleted as well. And when 19-202 is deleted, then 99-102 will be deleted from the basket.

NOTE: Use of checkboxes for this type of thing can be hazardous, as they do not pass a value when unchecked. It is preferable to use radio groups or select/drop-down widgets. If you must use checkboxes, be sure to explicitly clear mv_order_group and mv_order_item somewhere on the page which contains the form:

    [value name=mv_order_group set='']
    [value name=mv_order_item set='']

The attributes mv_mi and mv_si are set to the group and sub-item status of each item. The group, contained in the attribute mv_mi, is a meaningless yet unique integer. All items in a group will have the same value of mv_mi. The attribute mv_si is set to 0 if the item is a master item, and 1 if it is a sub-item.

1.6. Basket display

The basket page(s) are where the items are tracked and adjusted by the customer. It is possible to have an unlimited number of basket pages. It is also possible to have multiple shopping carts, as in buy or sell. This allows a basket/checkout type of ordering scheme, with custom order pages for items which have many accessories.

The name of the page to display can be configured in several ways:

  1. Set the SpecialPage order to the page to display when an item is ordered.
  2. Use the [order code=item page=page_name] Order it! </a> form of order tag to specify an arbitrary order page for an item.
  3. If already on an order page, set the mv_orderpage, mv_nextpage, mv_successpage, or mv_failpage variables.

The following variables can be used to control cart selection and page display:

mv_cartname

mv_failpage

mv_nextpage

mv_orderpage

mv_successpage

mv_order_profile

1.7. Multiple Shopping Carts

Interchange allows you to define and maintain multiple shopping carts. One shopping cart -- main, by name -- is defined when the user session starts. If the user orders item M1212 with the following tag:

    [order code=M1212 cart=layaway] Order this item! </a>

the order will be placed in the cart named layaway. However, by default you won't see the just-ordered item on the basket page. That is because the default shopping basket displays the contents of the 'main' cart only. So copy the default basket page (pages/ord/basket.html in the demo) to a new file, insert a [cart layaway] tag, and specify it as the target page in your [order] tag:

    [order code=M1212 cart=layaway page=ord/lay_basket] Order this item! </a>

Now the contents of the layaway cart will be displayed. Most of the ITL tags that are fundamental to cart display accept a 'cartname' option, allowing you to specify which cart to be used:

[cart cartname]

[item-list cartname]...[/item-list]

[nitems cartname]

[subtotal cartname]

[shipping cartname], [handling cartname], [salestax cartname], [total-cost cartname]

You can also order items from a form, using the mv_order_item, mv_cartname, and optional mv_order_quantity variables.

 <FORM METHOD=POST ACTION="[process]">
 <input type=checkbox name="mv_order_item" value="M3243"> Item M3243
 <input name="mv_order_quantity" value="1"> Quantity
 <input type=hidden name="mv_cartname" value="layaway">
 <input type=hidden name="mv_doit" value="refresh">
 <input type=submit name="mv_junk" value="Place on Layaway Now!">
 </FORM>

If you need to utilize an alternative item price in conjunction with the use of a custom cart, see the section on PRODUCT PRICING for pricing methods and strategies.

2. PRODUCT PRICING

Interchange maintains a price in its database for every product. The price field is the one required field in the product database -- it is necessary to build the price routines.

For speed, Interchange builds the code that is used to determine a product's price at catalog configuration time. If you choose to change a directive that affects product pricing you must reconfigure the catalog.

2.1. Simple pricing

The simplest method is flat pricing based on a fixed value in the products database. If you put that price in a field named price, you don't need to do more. If you want to change pricing based on quantity, size, color or other factors read on.

2.2. Price Maintenance with CommonAdjust

A flexible chained pricing scheme is available when the CommonAdjust directive is set.

We talk below about a CommonAdjust string; it will be defined in due time.

A few rules about CommonAdjust, all assuming the PriceField directive is set to price:

1

If CommonAdjust is set to any value, a valid CommonAdjust string or not, extended price adjustments are enabled. It may also hold the default pricing scheme.

2

The price field may also hold a CommonAdjust string. It takes precedence over the default.

3

If the value of the CommonAdjust directive is set to a CommonAdjust string, and the price field is empty or specifically 0, then it will be used to set the price of the items.

4

If no CommonAdjust strings are found, then the price will be 0, subject to any later application of discounts.

5

If another CommonAdjust string is found as the result of an operation, it will be re-parsed and the result applied. Chaining is retained; a fallback may be passed and will take effect.

Prices may be adjusted in several ways, and the individual actions are referred to below as atoms. Price atoms may be final, chained, or fallback. A final price atom is always applied if it does not evaluate to zero. A chained price atom is subject to further adjustment. A fallback price atom is skipped if a previous chained price was not zero.

Atoms are separated by whitespace, and may be quoted (although there should not normally be whitespace in a setting). A chained item ends with a comma. A fallback item has a leading semi-colon. Final atoms have no comma appended or semi-colon prepended.

A settor is the means by which the price is set. There are eight different types of price settors. All settors can then yield another CommonAdjust string.

It is quite possible to create endless loops, so the maximum number of initial CommonAdjust strings is set to 16, and there may be only 32 iterations by default before the price will return zero on an error. (The maximum iterations is specified with the Limit directive.)

NOTE: Common needs are easily shown but not so easily explained; skip to the examples in the reference below if your vision starts to blur when reading the next section. 8-)

USAGE: Optional items below have asterisks appended. The asterisk should not be used in the actual string. Optional base or table always defaults to the active products database table. The optional key defaults to the item code except in a special case for the attribute-based lookup. The field name is not optional except in the case of an attribute lookup.

N.NN or -N.NN

N.NN%

table*:column:key*

table*:col1..col5,col10:key*

        pricing:p1,p2,p3,p4,p5,p10:
        pricing:p1..p5,p10:

==attribute:table*:column*:key*

& CODE

      $Vend::Interpolate::item          is the current item
      $Vend::Interpolate::item->{code}  gives key for current item
      $Vend::Interpolate::item->{size}  gives size for current item (if there)
      $Vend::Interpolate::item->{mv_ib} gives database ordered from

[valid Interchange tags]

$

>>word

word

( settor )

2.3. CommonAdjust Examples

Most examples below use an outboard database table named pricing, but any valid table including the products table can be used. We will refer to this pricing table:

  code    common  q1     q5     q10    XL    S      red
  99-102          10     9      8      1     -0.50  0.75
  00-343                               2
  red      0.75

The simplest case is a straight lookup on an attribute; size in this case.

  10.00, ==size:pricing

With this value in the price field, a base price of 10.00 will be adjusted with the value of the size attribute. If size for the item 99-102 is set to XL then 1.00 will be added for a total price of 11.00; if it is S then .50 will be subtracted for a total price of 9.50; for any other value of size no further adjustment would be made. 00-343 would be adjusted up 2.00 only for XL.

  10.00, ==size:pricing, ==color:pricing

This is the same as above, except both size and color are adjusted for. A color value of red for item code 99-102 would add 0.75 to the price. For 00-343 it would have no effect.

  10.00, ==size:pricing, ==color:pricing:common

Here price is set based on a common column, keyed by the value of the color attribute. Any item with a color value of red would have 0.75 added to the base price.

  pricing:q1,q5,q10:, ;10.00, ==size:pricing, ==color:pricing:common

Here is a quantity price lookup, with a fallback price setting. If there is a valid price found at the quantity of 1, 5, or 10, depending on item quantity, then it will be used. The fallback of 10.00 only applies if no non-zero/non-blank price was found at the quantity lookup. In either case, size/color adjustment is applied.

  pricing:q1,q5,q10:, ;10.00 ==size:pricing, ==color:pricing:common

Removing the comma from the end of the fallback string stops color/size lookup if it reaches that point. If a quantity price was found, then size and color are chained.

  pricing:q1,q5,q10:, ;products:list_price, ==size:pricing, ==color:pricing

The value of the database column list_price is used as a fallback instead of the fixed 10.00 value. The above value might be a nice one to use as the default for a typical retail catalog that has items with colors and sizes.

2.4. PriceBreaks, discounts, and PriceAdjustment

There are several ways that Interchange can modify the price of a product during normal catalog operation. Several of them require that the pricing.asc file be present, and that you define a pricing database. You do that by placing the following directive in catalog.cfg:

  Database  pricing pricing.asc 1

NOTE: PriceAdjustment is slightly deprecated by CommonAdjust, but will remain in use at least through the end of Version 3 of Interchange.

Configurable directives and tags with regard to pricing:

For example, if you decided to adjust the price of T-shirt part number 99-102 up 1.00 when the size is extra large and down 1.00 when the size is small, you would have the following directives defined in <catalog.cfg>:

  Database          pricing pricing.asc 1
  UseModifier       size
  PriceAdjustment   size

To enable automatic modifier handling, you define a size field in products.txt:

  code    description   price    size
  99-102  T-Shirt       10.00    S=Small, M=Medium, L=Large*, XL=Extra Large

You would place the proper tag within your [item-list] on the shopping-basket or order page:

    [item-accessories size]

In the pricing.asc database source, you would need:

  code      S       XL
  99-102    -1.00   1.00

If you want to assign a price based on the option, precede the number with an equals sign:

  code    S       M       L       XL
  99-102  =9.00   =10     =10     =11

IMPORTANT NOTE: Price adjustments occur AFTER quantity price breaks, so the above would negate anything set with the PriceBreaks directive/option.

Numbers that begin with an equals sign (=) are used as absolute prices and are interpolated for Interchange tags first, so you can use subroutines to set the price. To facilitate coordination with the subroutine, the session variables item_code and item_quantity are set to the code and quantity of the item being evaluated. They would be accessed in a global subroutine with $Vend::Session->{item_code} and $Vend::Session->{item_quantity}.

The pricing information must always come from a database because of security.

2.5. Item Attributes

Interchange allows item attributes to be set for each ordered item. This allows a size, color, or other modifier to be attached to a common part number. If multiple attributes are set, then they should be separated by commas. Previous attribute values can be saved by means of a hidden field on a form, and multiple attributes for each item can be stacked on top of each other.

The configuration file directive UseModifier is used to set the name of the modifier or modifiers. For example

    UseModifier        size,color

will attach both a size and color attribute to each item code that is ordered.

IMPORTANT NOTE: You may not use the following names for attributes:

    item  group  quantity  code  mv_ib  mv_mi  mv_si

You can also set it in scratch with the mv_UseModifier scratch variable -- [set mv_UseModifier]size color[/set] has the same effect as above. This allows multiple options to be set for products. Whichever one is in effect at order time will be used. Be careful, you cannot set it more than once on the same page. Setting the mv_separate_items or global directive SeparateItems places each ordered item on a separate line, simplifying attribute handling. The scratch setting for mv_separate_items has the same effect.

The modifier value is accessed in the [item-list] loop with the [item-modifier attribute] tag, and form input fields are placed with the [modifier-name attribute] tag. This is similar to the way that quantity is handled, except that attributes can be "stacked" by setting multiple values in an input form.

You cannot define a modifier name of code or quantity, as they are already used. You must be sure that no fields in your forms have digits appended to their names if the variable is the same name as the attribute name you select, as the [modifier-name size] variables will be placed in the user session as the form variables size0, size1, size2, etc.

You can use the [loop arg="item item item"] list to reference multiple display or selection fields for modifiers, or you can use the built-in [PREFIX-accessories ...] tags available in most Interchange list operations. The modifier value can then be used to select data from an arbitrary database for attribute selection and display.

Below is a fragment from a shopping basket display form which shows a selectable size with "sticky" setting. Note that this would always be contained within the [item_list] [/item-list] pair.

    <SELECT NAME="[modifier-name size]">
    <OPTION  [selected [modifier-name size] S]> S
    <OPTION  [selected [modifier-name size] M]> M
    <OPTION  [selected [modifier-name size] L]> L
    <OPTION [selected [modifier-name size] XL]> XL
    </SELECT>

It could just as easily be done with a radio button group combined with the [checked ...] tag.

Interchange will automatically generate the above select box when the [accessories <code size]> or [item-accessories size] tags are called. They have the syntax:

   [item_accessories attribute*, type*, field*, database*, name*, outboard*]

   [accessories code attribute*, type*, field*, database*, name*, outboard*]

code

attribute

type

      select          Builds a dropdown <SELECT> menu for the attribute.
                      NOTE: This is the default.
    
      multiple        Builds a multiple dropdown <SELECT> menu for the
                      attribute.  The size is equal to the number of
                      option choices.
    
      display         Shows the label text for *only the selected option*.
    
      show            Shows the option choices (no labels) for the option.
    
      radio           Builds a radio box group for the item, with spaces
                      separating the elements.
    
      radio nbsp      Builds a radio box group for the item, with &nbsp;
                      separating the elements.
    
      radio left n    Builds a radio box group for the item, inside a
                      table, with the checkbox on the left side. If "n"
                      is present and is a digit from 2 to 9, it will align
                      the options in that many columns.
    
      radio right n   Builds a radio box group for the item, inside a
                      table, with the checkbox on the right side. If "n"
                      is present and is a digit from 2 to 9, it will align
                      the options in that many columns.
    
      check           Builds a checkbox group for the item, with spaces
                      separating the elements.
    
      check nbsp      Builds a checkbox group for the item, with &nbsp;
                      separating the elements.
    
      check left n    Builds a checkbox group for the item, inside a
                      table, with the checkbox on the left side. If "n"
                      is present and is a digit from 2 to 9, it will align
                      the options in that many columns.
    
      check right n   Builds a checkbox group for the item, inside a
                      table, with the checkbox on the right side. If "n"
                      is present and is a digit from 2 to 9, it will align
                      the options in that many columns.

field

database

name

outboard

When called with an attribute, the database is consulted and looks for a comma-separated list of attribute options. They take the form:

    name=Label Text, name=Label Text*

The label text is optional -- if none is given, the name will be used.

If an asterisk is the last character of the label text, the item is the default selection. If no default is specified, the first will be the default. An example:

    [item_accessories color]

This will search the product database for a field named "color". If an entry "beige=Almond, gold=Harvest Gold, White*, green=Avocado" is found, a select box like this will be built:

    <SELECT NAME="mv_order_color">
    <OPTION VALUE="beige">Almond
    <OPTION VALUE="gold">Harvest Gold
    <OPTION SELECTED>White
    <OPTION VALUE="green">Avocado
    </SELECT>

In combination with the mv_order_item and mv_order_quantity variables this can be used to allow entry of an attribute at time of order.

If used in an item list, and the user has changed the value, the generated select box will automatically retain the current value the user has selected.

The value can then be displayed with [item-modifier size] on the order report, order receipt, or any other page containing an [item-list].

2.6. Product Discounts

Product discounts can be set upon display of any page. The discounts apply only to the customer receiving them, and are of one of three types:

    1. A discount for one particular item code (key is the item-code)
    2. A discount applying to all item codes (key is ALL_ITEMS)
    3. A discount for an individual line item (set the mv_discount attribute
       with embedded Perl)
    4. A discount applied after all items are totaled
       (key is ENTIRE_ORDER)

The discounts are specified via a formula. The formula is scanned for the variables $q and $s, which are substituted for with the item quantity and subtotal respectively. The variable $s is saved between iterations, so the discounts are cumulative. In the case of the item and all items discount, the formula must evaluate to a new subtotal for all items of that code that are ordered. The discount for the entire order is applied to the entire order, and would normally be a monetary amount to subtract or a flat percentage discount.

Discounts are applied to the effective price of the product, including any quantity discounts or price adjustments.

To apply a straight 20% discount to all items:

    [discount ALL_ITEMS] $s * .8 [/discount]

or with named attributes:

    [discount code=ALL_ITEMS] $s * .8 [/discount]

To take 25% off of only item 00-342:

    [discount 00-342] $s * .75 [/discount]

To subtract $5.00 from the customer's order:

    [discount ENTIRE_ORDER] $s - 5 [/discount]

To reset a discount, set it to the empty string:

    [discount ALL_ITEMS][/discount]

Perl code can be used to apply the discounts, and variables are saved between items and are shared with the [calc] tag. This example gives 10% off if two items are ordered, with 5% more for each additional up to a maximum of 30% discount:

    [calc]
        [item-list]
            $totalq{"[item-code]"} += [item-quantity];
        [/item-list]
            return '';
    [/calc]

    [item-list]
        [discount code="[item-code]"]
            return ($s)       if $totalq{"[item-code]"} == 1;
            return ($s * .70) if $totalq{"[item-code]"} > 6;
            return ($s * ( 1 - 0.05 * $totalq{"[item-code]"} ));
        [/discount]
    [/item-list]

Here is an example of a special discount for item code 00-343 which prices the second one ordered at 1 cent:

    [discount 00-343]
    return $s if $q == 1;
    my $p = $s/$q;
    my $t = ($q - 1) * $p;
    $t .= 0.01;
    return $t;
    [/discount]

If you want to display the discount amount, use the [item-discount] tag.

    [item-list]
    Discount for [item-code]: [item-discount]
    [/item-list]

Finally, if you want to display the discounted subtotal, you need to use the [calc] capability:

    [item-list]
    Discounted subtotal for [item-code]: [currency][calc]
                                            [item-price] * [item-quantity]
                                            [/calc][/currency]
    [/item-list]

3. Taxing

Interchange allows taxing in a number of ways.

Simple salestax.asc table

The SalesTax directive is set to a form field or fields for user input, and those form fields are used look up the tax rate in salestax.asc.

Fly tax

Another simple tax method. A series of Interchange Variable settings are read to develop a salestax rate for one or a few localities, usually a state in the US.

Salestax multi -- VAT taxing

The country and state tables are used to develop complex VAT or salestax rate calculations based on country and state, possibly with different rates based on product type.

Levies -- multiple levels of tax

Using the Levies setting and the Levy structure, any or all of the above methods is used to implement one or more taxes.

3.1. Sales Tax -- simple salestax.asc table

Interchange allows calculation of sales tax on a straight percentage basis, with certain items allowed to be tax-exempt. To enable this feature, the directive SalesTax is initialized with the name of a field (or fields) on the order form. Commonly, this is zipcode and/or state:

    SalesTax    zip,state

This being done, Interchange assumes the presence of a file salestax.asc, which contains a database with the percentages. Each line of salestax.asc should be a code (again, usually a five-digit zip or a two letter state) followed by a tab, then a percentage. Example:

        DEFAULT 0.0
    45056   .0525
    61821   .0725
    61801   .075
    IL      .0625
    OH      .0525
    VAT     .15
    WA      .08

Based on the user's entry of information in the order form, Interchange will look up (for our example SalesTax directive) first the zip, then the state, and apply the percentage to the SUBTOTAL of the order. The subtotal will include any taxable items, and will also include the shipping cost if the state/zip is included in the TaxShipping directive. It will add the percentage, then make that available with the [salestax] tag for display on the order form. If no match is found, the entry DEFAULT is applied -- it is normally zero.

If business is being done on a national basis, it is now common to have to collect sales tax for multiple states. If you are doing so, it is possible to subscribe to a service which issues regular updates of the sales tax percentages -- usually by quarterly or monthly subscription. Such a database should be easily converted to Interchange format -- but some systems are rather convoluted, and it will be well to check and see if the program can export to a flat ASCII file format based on zip code.

If some items are not taxable, then you must set up a field in your database which indicates that. You then place the name of that field in the NonTaxableField directive. If the field for that item evaluates true on a yes-no basis (i.e. is set to yes, y, 1, or the like), sales tax will not be applied to the item. If it evaluates false, it will be taxed.

If your state taxes shipping, use the TaxShipping directive. Utah and Nevada are known to tax shipping -- there may be others.

If you want to set a fixed tax for all orders, as might occur for VAT in some countries, just set the SalesTax directive to a value like tax_code, and define a variable in the user session to reflect the proper entry in the salestax.asc file. To set it to 15% with the above salestax.asc file, you would put in a form:

    <INPUT TYPE=hidden NAME=tax_code VALUE="VAT">

or to do it without submitting a form:

    [perl] $Values->{tax_code} = 'VAT'; return; [/perl]

3.2. Fly tax

The [fly-tax] tag is placed in the DEFAULT setting of salestax.asc, and the variables TAXAREA, TAXRATE, and TAXSHIPPING are used to build the rates.

TAXAREA

A space-separated or comma-seperated list of states to apply tax to. Not needed for anything in the calculation, it is used to build the UI list of states to tax.

TAXRATE

An Interchange accessory-list style of value, with the format

  XX=N.NN, XX=N.NN

where XX is the two-letter state code and N.NN is the tax rate in percent. To apply a tax of 7.25% for Illinois and 5.5% for Nevada, you would use:

IL=7.25, NV=5.5

TAXSHIPPING

A space- or comma-separated list of states where shipping is taxed. For the above example, if Nevada taxed shipping and Illinois did not, you would make TAXSHIPPING equal to "NV".

The Salestax Directive

To set the field that is used for the state code, you use the standard Interchange SalesTax directive. It would almost always be set to state.

3.3. Salestax "multi" -- VAT taxing

If the SalesTax directive is set to "multi", then the type of tax is read from the country table. To see the tax type in force for the UK, you can place in a page:

        [data table=country col=tax key="UK"].
  MV_COUNTRY_TABLE      Table for country info (default "country")
  MV_COUNTRY_FIELD      Form field determining country (default "country")
  MV_COUNTRY_TAX_FIELD  Table column for country-wide tax (default "tax")
  MV_STATE_TABLE        Table for state/province info (default "state")
  MV_STATE_FIELD        Form field determining state/province (default "state")
  MV_STATE_TAX_FIELD    Table column for state-wide tax (default "tax")
  MV_TAX_TYPE_FIELD     Table column enumerating tax types (default "tax_type")
  MV_TAX_CATEGORY_FIELD Table column for product type (default tax_category)

Below, we refer to the tables, columns, and fields by their default names.

The first lookup is done in table country based on the user input of country (i.e. [value country]). The tax field is read and one of the following is done:

1. If no string is found, tax returns 0.

2. If string "simple:XX" is found, uses [fly-tax] with the area specifed in XX.

3. If string "state" is found, does a re-lookup with

     select tax from state where country = country and state = state

and value is applied as below.

4. If just digits are found, rate applied directly -- i.e. "0.05"

5. If N.NN% is found, applied as percentage.

6. If category = N.NN%, default = N.NN% is found, the tax_category field in the products table is used to determine tax basis. If no tax_category is found for the product, default rate is used.

This product data

    sku      price     tax_category
    os28003  10.00     tools
    os28004  20.00     food

with this country and state data:

    code     name     tax
    US       U.S.A.   state
    JP       Japan    tools=10%, default=15%


    code   country   state   name      tax
    0001   US        IL      Illinois  6.5%
    0002   US        OH      Ohio      default = 5.5%, food = 1%
    0003   US        AZ      Arizona

Will yield tax for one each of os28003 and os28004 of:

    Japan   $4.00
    US/IL   $1.95
    US/OH   $0.75
    US/AZ   $0.00

4. THE CHECKOUT PROCESS

4.1. Advanced Multi-level Order Pages

An unlimited number of order checking profiles can be defined with the OrderProfile directive, or by defining order profiles in scratch variables. This allows a multi-level ordering process, with checking for format and validity at every stage.

To custom-configure the error message, place it after the format check requirement.

Specifications take the form of an order page variable (like name or address), followed by an equals sign and one of five check types:

required

mandatory

phone

phone_us

state

province

state_province

zip

ca_postcode

postcode

true

false

email

regex

            foo=regex ^bar
       foo=regex ^bar "You must have bar at the beginning of this"
       foo=regex !^bar "You may not have bar at the beginning!"

length

       foo=length 4-10

unique

       foo=unique userdb Sorry, that username is already taken

filter

       foo=filter entities Sorry, no HTML allowed
            foo=filter lower Sorry, no uppercase characters

Also, there are pragmas that can be used to change behavior:

&charge

&credit_card

        # Checks credit card number and destroys number after encryption
        # The charge operation can never work
    
        &credit_card=standard
        &charge=custom authorizenet
    
        # Checks credit card number and keeps number after encryption
        # The charge operation can now work
    
        &credit_card=standard keep
        &charge=custom authorizenet
        &credit_card=check_cc

&fail

        &fail=page4

&fatal

&final

&update

&return

        # Success :)
        &return 1
    
        # Failure :\
        &return 0

&set

&setcheck

&success

        &success=page5

As an added measure of control, the specification is evaluated for the special Interchange tags to provide conditional setting of order parameters. With the [perl] [/perl] capability, quite complex checks can be done. Also, the name of the page to be displayed on an error can be set in the mv_failpage variable.

The following file specifies a simple check of formatted parameters:

 name=required You must give us your name.
 address=required Oops! No address.
 city=required
 state=required
 zip=required
 email=required
 phone_day=phone_us XXX-XXX-XXXX phone-number for US or Canada
 &fatal=yes
 email=email Email address missing the domain?
 &set=mv_email [value email]
 &set=mv_successpage ord/shipping

The profile above only performs the &set directives if all of the previous checks have passed -- the &fatal=yes will stop processing after the check of the email address if any of the previous checks failed.

If you want to place multiple order profiles in the same file, separate them with __END__, which must be on a line by itself.

User-defined check routines can be defined in a GlobalSub:

    GlobalSub <<EOF
    sub set_up_extra_check {
        BEGIN {
            package Vend::Order;
            sub _pt_postcode {
                # $ref is to Vend::Session->{'values'} hash
                # $var is the passed name of the variable
                # $val is current value of checked variable
                my($ref, $var, $val) = @_;

                if ($ref->{country} =~ /^(PT|portugal)$/i) {
                    return $val =~ /^\d\d\d\d$/ ?
                        (1, $var, '') : (undef, $var, "not a Portugese postal code");
                }
                else {
                    return (1, $var, '');
                }
            }
        }
    }
    EOF

Now you can specify in an order profile:

  postcode=pt_postcode

Very elaborate checks are possible. There must be an underscore preceding the routine name. The return value of the subroutine should be a three-element array, consisting of:

  1. the pass/fail ('1' or 'undef') status of the check;
  2. the name of the variable which was checked;
  3. a standard error message for the failure, in case a custom one has not been specified in the order profile.

The latter two elements are used by the [error] tag for on-screen display of form errors. The checkout page of the Foundation demo includes examples of this.

4.2. Simple Order Report File

The simple order report file, "report", defines the layout of the order report which gets mailed on the completion of the order. For example,

              Order Date: $date

                    Name: $name
           Email address: $email

        Shipping address: $addr
        Town, State, Zip: $town, $state $zip
                 Country: $country

Any input field from the order page can be included using the dollar sign notation.

Interchange defines some values for use in the search form -- they begin with mv_ and are automatically ignored.

4.3. Fully-configurable Order Reports

You can specify a fully-configurable order report by setting the hidden field "mv_order_report" to a legal Interchange page. This page will be interpolated with all Interchange tags before sending by email. The order number as set by backend ordering is in the variable mv_order_number, and available for your use.

You could if you wish include HTML in the file, which will be interpreted by many mailers, but you can choose to use standard ASCII format. An example report is provided in the demo file <pages/ord/report.html>.

4.4. Order Receipts

The file can of course be configured with all Interchange tags, and will be interpolated for the ordered items before they are deleted from the user session. You can set the default receipt with the receipt key in SpecialPage. If using order Routes, as in the foundation demo, you set it with the receipt key to Route.

4.5. The Order Counter

An order counter can be enabled if the OrderCounter directive is set to a file name. An incrementing count of all orders will be kept and assigned as orders are placed. By default, the number starts at 0, but you can edit the file and change the default starting number at any time.

This capability is made possible by the File::CounterFile module, available (as a part of the fine libwww modules) at the same place you got Interchange. It is included with the distribution.

4.6. Customer Input Fields

On the order (or shopping basket) page, by default order.html, you will have a number of input fields allowing the customer to enter information such as their name and address. You can add more fields simply by putting more input elements on the order.html page, and the information will automatically be included in the order report. Input elements should be written in this way:

    <input type="text" name="town" value="[value town]" size=30>

Choose a name for this input field such as "email" for an email address. Set the name attribute to the name you have chosen.

The value attribute specifies the default value to give the field when the page is displayed. Because the customer may enter information on the order page, return to browsing, and come back to the order page, you want the default value to be what was entered the first time. This is done with the [value var] element, which returns the last value of an input field. Thus,

    value="[value name]"

will evaluate to the name entered on the previous order screen, such as:

       value="Jane Smith"

which will be displayed by the browser.

The size attributes specifies how many characters wide the input field should be on the browser. You do not need to set this to fit the longest possible value since the browser will scroll the field, but you should set it large enough to be comfortable for the customer.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Interchange + CVS HOWTO

5. Introduction

5.1. Preamble

Copyright 2001-2003 Dan Browning <dan.browning@kavod.com>. This document is freely redistributable under terms of the GNU General Public License.

5.2. Purpose

The purpose of this document is to help others take advantage of CVS and Interchange together to increase the quality of their programming, whether they are sole developers or part of a large team of programmers, graphic artists, and HTML design gurus. Portions of it apply to general CVS setup and use, but it is geared toward the average developer using Interchange to implement an e-commerce website.

5.3. Audience

I intend for this document to be useful to those who are not yet familiar with CVS as well as those who are. If you already know how to setup a pserver then you might just skim chapter 2 ("Setup CVS"), or skip it all together.

In addition, I have tried to write at a technical level that would be on par with what I perceive to be the average Interchange user that participates on the interchange-users mailing list. It is assumed that the reader can and already has setup Interchange and the template catalog (e.g. Foundation) is working correctly.

5.4. Contact the author

If you find any spelling errors, technical slip-ups, mistakes, subliminal messages, or if you wish to send feedback, critique, remarks, comments, or if you wish to contribute examples, instructions for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context diff against the SDF source file (ic_cvs.sdf). Please address your correspondence to:

Dan Browning dan.browning@kavod.com

5.5. The advantages of using CVS

CVS is a very useful tool and can help you in your development, no matter if you are an independant developer or are part of a team of developers.

The official CVS website (http://www.cvshome.org/new_users.html) has more detailed answers to these questions, but here are some brief points of interest.

5.6. How to use this document

There are many potential uses of CVS as it applies to Interchange. In fact, there are as many unique ways to use CVS as there are unique developers. This document only covers some of the ways, including basic and useful techniques to get started using CVS. For the intents of the average web developer using IC for a B2C e-commerce site, I've identified a few of the possible uses:

Simple

Medium

Complex/Custom

This document attempts to cover the simple well, explain many aspects of the medium, and hopefully give you the background you need if you decide to setup your own complex development environment.

6. Setup CVS

6.1. Assumptions

Here are some of the assumptions that I make that apply to various parts of the rest of this document:


Note: I will assume "foundation" for the catalog name and directory paths, but it should be just as easy to use this document with your own catalog by mentally transposing the names and paths.

There shouldn't be any reason why you could not do everything I mention here on other Linux distributions, Unices or Windows (using cygwin). However, my statements will reflect Red Hat Linux 7.x. Additionally, Red Hat Linux 6.x is for the most part the same as 7.x, except for the difference of using inetd instead of xinetd to setup pserver.

6.2. Install CVS

This is the easy part. For Red Hat Linux systems, download the CVS rpms and install them. You can search for rpms for your system using http://www.rpmfind.net.

Create the user and group that will administrate the Interchange repository. For this document, it will be the interch user, (which was setup during the installation of Interchange). But if you understand the mechanics of Unix users/groups, then you can use whatever username and group scheme you prefer. For example, some create a cvs user and add it to the same group that interchange uses (e.g. interch), or add the Interchange user and catalog owner to its group or vice-versa. The integration of Interchange and CVS in the latter portion of this document will require that the CVS user can write to the catalog directory.

6.3. Create the CVS repository directory

You will need to create a repository directory such as /home/interch/rep, which is used here and in the rest of the document, but it can be any directory you desire, and must be owned by the cvs user.

        mkdir /home/interch/rep

6.4. Setup environment variables

The CVSROOT environment variable can be setup for your user (in ~/.bashrc or ~/.profile, or for all users in /etc/profile.

~/.profile:

export CVSROOT=${HOME}/rep

6.4.1. .cvsrc

We recommend these default options for CVS.

~/.cvsrc:

cvs -q
diff -u
update -Pd
checkout -P

This directs CVS to (1) automatically compress all data communicated between you and our server (saving bandwidth), and be quieter; (2) show context-sensitive diffs; (3) prune empty directories and create any new directories added to the repository since your checkout; and (4) prune empty directories during your checkouts.


Note: You will need to logout/login for the profile changes to take effect.

6.5. Initialize the repository

Initialize the repository as the CVS user, which is interch for this document.

        cvs -d /home/interch/rep init

6.6. CVS Authentication

6.6.1. Background

Authentication is done in CVS through the $CVSROOT/CVSROOT/passwd file. It can be easily manipulated through some of the CVS administration tools that are available. An alternate authentication method is ssh, which requires no extra setup on the server side.

6.6.2. CVS administration tools

I recommend cvsadmin, but there are also a variety of manual methods that can be used in the absence of such tools, one of which involves copying the system shadow file and modifying it for use by CVS. For more information on this manual method, see the Red Hat CVS pserver setup guide by Michael Amorose (http://www.michael-amorose.com/cvs/).

6.6.3. Setup authentication using the cvsadmin tool

You can find a tarball to install on your system using the above address, but here is the address of a recent RPM package of the version. This package is intended for Mandrake systems, but is compatible with Red Hat Linux 7.1:

After installing, create a password file (touch $CVSROOT/CVSROOT/passwd, touch $CVSROOT/CVSROOT/users), and execute cvsadmin add <usernames>.

6.7. Setup CVS modules


Note: From this point on, assume that all commands are executed as the CVS user (e.g. interch), unless otherwise specified.

A module is CVS is like the concept of a "project", where each module has its own branches, trees, and other features.

6.7.1. Add your project to the modules configuration file

The format of the modules file is explained in detail in the CVS documentation, here is the simplest way to use it. First you will need to checkout your CVSROOT directory, then modify and commit the 'modules' file.


cvs co CVSROOT
cd CVSROOT

modules:


<Module name><TAB><Module Directory>

The module name can be whatever you want, and the module directory is what we will create later under /rep. We'll want a module for the template catalog (foundation). For example:

foundation      foundation

6.7.2. Create the module directory

This is the directory that is referred to in the CVSROOT/modules file we just modified.

mkdir /rep/foundation

6.8. Setup binary file types

This isn't necessary if you aren't going to manage any binary files (e.g. if you plan on excluding your images/ directory). But I recommend including it. The following is an example including many binary file types (by extension) used in web development.

/rep/CVSROOT/cvswrappers:

*.avi   -k 'b' -m 'COPY'
*.doc   -k 'b' -m 'COPY'
*.exe   -k 'b' -m 'COPY'
*.gif   -k 'b' -m 'COPY'
*.gz    -k 'b' -m 'COPY'
*.hqx   -k 'b' -m 'COPY'
*.jar   -k 'b' -m 'COPY'
*.jpeg  -k 'b' -m 'COPY'
*.jpg   -k 'b' -m 'COPY'
*.mov   -k 'b' -m 'COPY'
*.mpg   -k 'b' -m 'COPY'
*.pdf   -k 'b' -m 'COPY'
*.png   -k 'b' -m 'COPY'
*.ppt   -k 'b' -m 'COPY'
*.sit   -k 'b' -m 'COPY'
*.swf   -k 'b' -m 'COPY'
*.tar   -k 'b' -m 'COPY'
*.tgz   -k 'b' -m 'COPY'
*.tif   -k 'b' -m 'COPY'
*.tiff  -k 'b' -m 'COPY'
*.xbm   -k 'b' -m 'COPY'
*.xls   -k 'b' -m 'COPY'
*.zip   -k 'b' -m 'COPY'

6.8.1. Commit changes

Remember to commit the changes you made to 'modules' and 'cvswrappers'.

cvs commit -m "Update modules and binary types" modules cvswrappers

6.9. Setup the CVS pserver

You will likely need to be root to do this, and there are lots of guides on the Internet for setting up a CVS pserver, hopefully you wont have any trouble doing it on your particular operating system. See the Resources Appendix for more information.

6.9.1. Setup pserver in Red Hat Linux 7.x using xinetd.

For Red Hat Linux 7.x, edit /etc/xinetd.d/cvspserver (create a new one if none exists). The following works for me, but customization may be required for your environment (see the next section below for an inetd-based system example). This also must be done as root. Remember to substitue /home/interch/rep with your repository directory below.

su - root
/etc/xinetd.d/cvspserver:

service cvspserver
{
        disable = no
        socket_type  = stream
        protocol  = tcp
        wait   = no
        user    = root
        server   = /usr/bin/cvs
        server_args  = -f --allow-root=/home/interch/rep pserver
}

Now, restart xinetd for the changes to take effect.

service xinetd restart

6.9.2. Setup pserver in inetd-based systems.

For inetd-based systems such as Red Hat Linux 6.2, make sure that the following files are setup accordingly.

/etc/services:

cvspserver      2401/tcp
N:/etc/inetd.conf:

cvspserver stream tcp nowait \
        root /usr/sbin/tcpd /usr/bin/cvs \
        --allow-root=/home/interch/rep pserver

6.9.3. Testing your pserver

At this point, you should be able to use a CVS client to use your pserver and execute all the same commands that you can locally (which we tested before). You may wish to take advantage of a graphical CVS client, which can be particularly helpful in leveling the learning curve.

Your pserver connection string will something along the lines of:

 :pserver:<USERNAME>@<SERVER>:/home/interch/rep

See the Resources Appendix for links to some graphical CVS tools.

7. Import your Interchange catalog into CVS

7.1. Configuring your catalog

Eventually, we will import your catalog into the CVS repository, but first we need to do some work with a temporary copy of the catalog so we can get it into shape for importing.


Note: From here on, assume the use of the Interchange user, such as interch, unless otherwise noted.

su - interch

If you installed via RPM:

service interchange stop

If you installed via tarball (default path):

/usr/local/interchange/bin/interchange --stop

7.2. Remove old CVS folders

If, for any reason, you already have CVS/ directories in your catalog, they must be removed because they might interfere with the new CVS setup. You might use the following find command, which will find any folders named CVS in the current directory and remove them.

sNote:You should make a backup of the catalog directory before you do this.


#backup catalog folder first
tar czf ~/foundation_backup.tgz /var/lib/interchange/foundation

#get rid of any old CVS folders -- (BE CAREFUL!)
cd /var/lib/interchange/foundation
find . -name CVS -exec rm -Rf {} \;

7.3. Create a working copy of your catalog

A working copy of your catalog is necessary to get it into shape for use with CVS. The following command creates a copy in the /tmp directory.

cp -a /var/lib/interchange/foundation /tmp/import_foundation
cd /tmp/import_foundation

7.4. Streamline your catalog for CVS

7.4.1. Considerations about what to import into CVS

From your working directory (/tmp/import_foundation), decide which files will be in the CVS repository, and which will not. While it is entirely possible to import the entire catalog into the repository unchanged, I usually prefer to doctor my directories up before letting them into my repository because of several reasons:

For example, /etc/order.number is modified by Interchange when run. It is recommended that the CVSIGNORE features be used to handle these types of files. See CVSIGNORE.

For example, if I am certain that I wont every want to modify the session/ files directly, then I probably wouldn't need to manage that through CVS, but I do import the empty session/ directory to make it easier when setting up new catalogs.

Managing less files in the repository takes away from the amount of time required for CVS checkout, update, branching, and other CVS actions. For most, this amount of time is small already, but it is a consideration for some. If you have a very large image directory, it may be benificial to leave it out at first. Note that you can add or remove anything later on.

7.4.2. Remove files that aren't needed in CVS

Here is an example of some things to remove from your catalog. If you do move more directories, be sure to move them to a directory that you can later use to re-unite with a checked-out copy for a working catalog. But here I chose just to move files that are not needed for a template "skeleton" catalog.

If you want to add images to your repository, the images directory is typically symlinked to /var/www/html/foundation/images, so I remove this symlink from the working copy, and replace it with an exact copy which will go into the CVS repository.

#Setup images directory
rm images
cp -a /var/www/html/foundation/images .

#Remove
rm -Rf \
        error.log \
        *.structure \
        orders/* \
        logs/* \
        session/* \
        tmp/* \
        upload/* \
        backup/* \
        logs/* \
        #done.

# The ".empty" files make it so that CVS will still checkout the
# directory, even though it is empty.
touch \
        orders/.empty \
        logs/.empty \
        session/.empty \
        tmp/.empty \
        upload/.empty \
        backup/.empty \
        #done.

7.5. Import the streamlined catalog

Import the remaining portion of the catalog using the cvs import command, with "foundation" as the module name and repository directory name. See the CVS documentation resources mentioned in Appendix Resources for more information.

When you run the import command, it will launch $EDITOR (set to 'vi' earlier), and ask for a message to go along with the import action. Whatever you see fit to write (e.g. "starting new CVS module with my foundation catalog...") is fine.

This example import command includes renaming the foundation "working" directory back to "foundation" for the import.

cvs import foundation foundation start

7.6. Testing the new CVS module

Now you should be able to do another test checkout or update using any CVS client, which should now download all the files that you have just imported into CVS. Additionally, you might test your newly imported code by making a change to one of your checked-out source files, saving it, then committing it.

index.html:
<!--this is a test comment at the top of index.html-->

Now commit the change

cvs commit index.html

Your changed version will now be resident in the repository. There are a lot of good CVS documentation and resources for discovering more about the checkout/update/commit cycle and other CVS aspects in the Resources Appendix

You'll also notice that even if you start your interchange server, the change you made did not take effect. The next section will detail the process of tying CVS and Interchange together in a way that this will happen automatically.

8. Integrate CVS and Interchange

The next step is to allow CVS to update the directory that Interchange uses to serve pages.

8.1. CVS checkout into the catalog directory

Now it is the time to replace the directories in your catalog that have counterparts in CVS with fresh checkouts from CVS (this is a preliminary action to allow CVS to update your catalog directory when a change is made to CVS).


Note: Make sure interchange daemon is stopped and you have a good backup before continuing.

tar czf ~/foundation.backup2.tgz /var/lib/interchange/foundation

Checkout a copy from CVS into a different directory (such as foundation_CVS).

cd /var/lib/interchange/
cvs co -d foundation_CVS foundation

This should create the foundation_CVS/ directory for you, so that it wont conflict with your existing foundation/ directory.

8.1.1. Add any needed files to checked-out catalog

Note that empty directories are pruned, so they will need something in them for them to show up with a -P checkout. Often a zero-byte file called '.empty' is used.

If you removed any directories during the streamlining step, we must first add those back so that the catalog is usable to Interchange. In this document, we only removed unneeded files and left empty directories.

This can also be the time to copy any "data" files such as orders/ logs/, etc. that might be needed if it is a live catalog.

cd /var/lib/interchange/foundation
cp -a <NEEDED_FILES> \
        /var/lib/interchange/foundation_CVS

8.1.2. Install and test the new catalog

Now lets move the old foundation out of the way and put the new foundation_CVS in its place.

cd /var/lib/interchange/
mv foundation foundation_old
mv foundation_CVS foundation

Now, link up the CVS images for use by Apache.

cd /var/www/html/foundation/
mv images images_old
ln -s /var/lib/interchange/foundation/images images

Now, you should have a working catalog again. To make sure, start up Interchange and test the site with your browser.

8.2. Testing manual CVS updates on Interchange catalogs

Next, lets again update the checkout we made a while back before importing our catalog. (Alternatively, one could use a visual CVS client detailed above).

cd ~/src
cvs -q up -d foundation # -q for quiet, -d for directory prune/update

Additionally, you might test making a change to one of your checked-out source files, saving it, then committing it.

index.html:
<!--this is a test comment at the top of index.html-->

Now commit the change

cvs commit index.html

Your changed version will now be resident in the repository. Again, CVS documentation is in the Resources Appendix.

This time, we can allow the changes to take effect on the code being used by Interchange to serve pages. To do so, one must run a cvs update on the catalog directory:

cd /var/lib/interchange/foundation
cvs -q up -d    #up is the shortened version of "update"

That should notify you of the new version it downloaded with something like:

U pages/index.html

You may also get something like the following:

M catalog.cfg
M etc/status.foundation
M ...
? orders/000001
? ...

The ? lines in the above example mean that the CVS server has never heard of the listed directories or files (they are in your local source dir but not in the CVS source dir). It is harmless, but sometimes annoying, and can be taken care of with CVSIGNORE.

The M means that the file has been modified on your local copy, and is out of sync with the remote CVS version (e.g. when Interchange runs it updates etc/status.foundation). Normally this is corrected by uploading your "modified" version to the server, but in this case, the modification was done by Interchange instead of the programmer, and wasn't meant to be committed back to the CVS repository. See CVSIGNORE.

Now, check to make sure that your change has taken effect by refreshing the homepage on the site. To see the comment, use View->Page Source or whatever the relevant command for your browser is.

At this point, its obvious that it would be time consuming to manually run 'cvs up' every time you make a change to the source code, so the next step is to setup CVS to automatically update the catalog whenever you commit something to CVS.

8.3. Automatic updates on commit

Start by modifying $CVSROOT/CVSROOT/loginfo

^foundation     (date; cat; ( \
        sleep 1; cd /var/lib/interchange/foundation; cvs -q update -d \
        ) &) >> $CVSROOT/CVSROOT/updatelog 2>&1

The first line tells CVS that for every commit on modules that start with "foundation" (notice the regular expression "^foundation"), it will run cvs update on the given catalog directory in the background. It is important that it is executed in a forked shell (notice the "&") after sleep'ing for 1 second, because otherwise you may run into contention issues that can cause file locking problems. The 1 second timing used above works fine for me, but a longer pause may be necessary for slower computers (you'll know if you get errors about "file locked by user"). See the CVS documentation in the Resources Appendix for more details.

8.4. Automatic e-mail on commit

Often it is very helpful to have a commit mailing list that keeps developers up-to-date on every commit happening to the CVS. Perform these steps:

mkdir ~/src; cd ~/src
cvs co CVSROOT
cd CVSROOT
cvs up
wget \
        http://www.icdevgroup.org/~danb/log_accum.pl \
        http://www.icdevgroup.org/~danb/mailout \
        #done.
chmod u+x log_accum.pl mailout
cvs add log_accum.pl mailout
touch updatelog
cvs add updatelog
cat >>checkoutlist <<EOF
log_accum.pl
mailout
updatelog
EOF
# Fix Permissions for updatelog
cd $CVSROOT/CVSROOT
chmod g+w *
echo 'ALL $CVSROOT/CVSROOT/log_accum.pl %s' >> loginfo
cvs commit -m "Automatic E-mail" checkoutlist loginfo ${FN}

As root, you must setup the "cvs-log" alias to go to the correct e-mail address(es).

echo 'cvs-log: email_one@yahoo.com,email_two@yahoo.com' >> /etc/aliases
newaliases

See Mailserver for CVS updates.

Here is what a sample e-mail looks like:

User:      danb
Date:      2003-01-16 23:40:47 GMT
Modified:  pages    index.html
Log:
Testing...


Revision  Changes    Path
1.10      +1 -8      hoopstore/pages/index.html



rev 1.10, prev_rev 1.9
Index: index.html
===================================================================
RCS file: /home/interch/rep/hoopstore/pages/index.html,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- index.html  16 Jan 2003 22:47:55 -0000      1.9
+++ index.html  16 Jan 2003 23:40:47 -0000      1.10
@@ -31,7 +31,7 @@
   [control-set]
     [component]none[/component]
   [/control-set]
-
+

   [control reset=1]

@@ -51,10 +51,3 @@
 <!-- END CONTENT -->

 @_LEFTRIGHT_BOTTOM_@
-
-

Now you have a working CVS development system. At this point it may be valuable to learn more about CVS the client tools that you are using.

9. The two track model: development and live catalogs

It is often very valuable to have a two-track development model that separates the classes of work into separate timing and decision categories. Some use "staging" and "production" terminology, others prefer "unstable" and "stable", "beta" and "release", or "development" and "live".

The easiest starting point for two-track development is to just use two completely separate CVS modules and catalogs. This can make a lot of sense for many situations, for example when the next revision of the site will be so different that it is for all practical purposes starting from ground zero.

A slightly more complicated solution is to use the CVS branches feature. It is more difficult to set up, but can be rewarding when used correctly.

9.1. When to branch

The first decision is when to branch the source code. For websites, this can sometimes be an easy decision like "first went live", or "site-wide overhaul", etc.

9.2. Which way to branch

There are many different ways to branch source code. What seems to be the most common method is to use the "trunk", which is the HEAD tag to CVS as the development version, and then make a branch when a stable release is to be made.

That model doesn't fit my development style at the current time, so I use the HEAD default branch as my stable live version, and use other tags (like DEV1 and DEV_REALLY_UNSTABLE) for my development branch.

You may find that you are merging (or "folding") most or all of your development ranch back into your stable branch frequently. This is because unlike traditional programming where products are launched every two or three years with new features, web sites often have little fixes and new features added every day or every few weeks, with new "releases" happening more often than traditional software development (though not all web sites follow that trend). The flexibility is there to branch the source for quite some time to work on a very complex feature or complete redesign before bringing it to the live site, as well as the flexibility for day-to-day updates.

9.3. Performing the branch

To perform the branch use the cvs tag -b <BRANCH NAME> command. For example:

cvs tag -b DEV1

Remember that this does not change your locally checked out working directory to the new tag automatically, it only creates the branch within the CVS repository.

9.4. Setup the development catalog

Now we have a branch in CVS, but we need to tie it to something in the real world, namely, an Interchange catalog.

9.4.1. Importing the catalog

Like we did in Integrating CVS with Interchange, you must make another copy of your catalog for use as the development version. Some would like to keep the orders/, logs/, and other directories the same, but I prefer to start with a clean slate, especially since I don't plan on having any customers visit the development site. (In fact, you can restrict who can access the development URL using the Apache <Directory> allow from... directive).

9.4.1.1. Checkout source code

cd /var/lib/interchange
cvs co -d foundation_dev foundation

9.4.1.2. Copy any other needed directories to complete the catalog

Depending on how complete your catalog is in CVS, you may need to create or copy directories/files.

cd /var/lib/interchange/foundation
cp -a catalog.cfg orders/*   \
        /var/lib/interchange/foundation_dev


Note: A lot of the following steps are performed by the /usr/local/interchange/bin/makecat script, but here is how to do it manually:

9.4.2. Setting up a separate database

Most often, I find it profitable to make use of a second database for the development catalog, rather than having both catalogs reference the same database (especially if the first catalog is live).

9.4.2.1. Create a second database

Use the means of your database platform to create a separate database. For example, PostgreSQL users might do something like:

createdb foundation_dev

9.4.2.2. Populate the database

You can rely on the catalogs internal products/*.txt data to generate the database tables and populate them, or you can export another catalog's database and import it for the development catalog, like the example below for PostgreSQL users.

pg_dump foundation  > ~/foundation.dump
psql foundation_dev < ~/foundation.dump

9.4.3. Copy the catalog support files

#Must be root
su - root

#Copy HTML
cd /var/www/html/
cp -a foundation foundation_dev

#Copy CGI
cd /var/www/cgi-bin
cp -a foundation foundation_dev

9.4.4. Configure the Interchange daemon

Perform the necessary modifications to interchange.cfg. For example:

/usr/local/interchange/interchange.cfg:
Catalog found     /var/lib/interchange/foundation     /cgi-bin/foundation
Catalog found_dev /var/lib/interchange/foundation_dev /cgi-bin/foundation_dev

9.4.5. Configure the catalog specifics

The development catalog will differ at least a little bit from the standard catalog, such as in the CGI_URL and database parameters. I recommend using a separate "local" configuration file to hold the separate values, such as config/local.cfg, and then include it from catalog.cfg.

/var/lib/interchange/config/local.cfg:
Variable CGI_URL   /cgi-bin/foundation_dev
Variable IMAGE_DIR /foundation_dev/images

Now you can restart Interchange to make your changes take effect.

9.5. Splitting updates on commit by tag

Setup CVS so that when you commit to the DEV1 branch, only the development (foundation_dev) catalog will be updated. And when you commit with no tags (HEAD branch), the live (foundation) catalog will be updated. Here is an example loginfo. The -r <tag> may be used just in case your environment is such that the tags may be changed by other sources.

$CVSROOT/CVSROOT/loginfo:
foundation   \
        (date; cat; ( \
        sleep 1; cd /var/lib/interchange/foundation_dev; cvs -q up -d; \
        cd /var/lib/interchange/foundation; \
        cvs -q up -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1
ALL     /usr/bin/cvs-log     $CVSROOT/CVSROOT/commitlog $USER "%{sVv}"

9.6. Using new branches

To use your new branch, checkout a working copy of the source with the correct tag specified. For example:

cvs co -P -r DEV1

Then make change to one of the files, and commit it. The change should show on your development catalog, but not your live catalog.

9.7. Merging

When you want to merge a change that you have made on your development branch into your stable branch, there are many ways that you can do it. One would be to :

I do the above so often that I have written a Tcl script for WinCVS that will automatically perform the above steps. And similar shell scripts can probably be easily written to match your development environment.

The above seems to be the easiest way, to me. However, there are other alternatives detailed in the CVS manual in chapter 5, "Branching and merging", that I highly recommend for reading. One method involves specifying the last version that has already been merged into the live branch using a specific version number, date, relative time, or special purpose tag.

10. Tools of the trade

This is the productivity tips section, which will hopefully help you to be able to get more done in less time.

10.1. Workstation Interchange installation

Not all developers work on Linux workstations, many use Apples (graphics designers and HTML gurus tend to, I've found), and many use Windows. This means that many developers have the extra step of uploading their changes to a Unix server where Interchange is running in order to see their changes.

The remedy to that is to setup an Interchange server on your workstation, or any location that has direct access to the CVS source files. I'll explain:

The Interchange server that runs where the CVS server is (that we setup earlier) can be seen as the gathering point for all the developers. However, each developer may run as many Interchange daemons as he/she requires in a local context for the purpose of seeing the changes made before uploading them via CVS.

For example, Bob could setup another Interchange catalog on the same server as the CVS, (e.g. foundation-bob). To get direct access to those files (rather than FTP), Bob could use NFS mounts (if Bob's workstation is Linux) or SMB mounts using Samba if his workstation is a Windows variant. Any way that Bob can get direct access to the files will save him some time (by cutting out the "upload" from the "edit->upload->test" development cycle). One could even use VMware to run a Linux server on your Windows workstation.


Note: You can now use the cygwin compatibility confirmed in Interchange versions 4.7.6 and above to run Interchange right on your Windows workstation.

The result will be that you can modify the files with your favorite text editor and see the results immediately through your local catalog. Setting up the catalog initially is quite easy. Just follow the same steps used to setup the CVS catalog. Which is:

Variable CGI_URL        /cgi-bin/foundation
Variable SERVER testserver
Variable SECURE_ENABLE  0
Variable IMAGE_DIR      /foundation/images

You may need to remove all *.sql files from the products directory, to create all of the database files again. Additionally, you may need to create the database, username/password for your database again as well.

You will need to recreate any symbolic links that previously existed, such as templates/default -> templates/foundation

Another thing that you might have noticed at this point is all the files that are modified locally by the Interchange daemon will report ? or M when you run an update. To fix this, see CVSIGNORE.

10.2. CVSIGNORE

On the heals of a workstation installation is the requirement to setup CVSIGNORE. For all files that change, but you want to ignore (such as etc/foundation.status), create an entry in the .cvsignore file in that directory. Note that the file must be removed from the cvs repository before it will work.

Here is a script that will create some sample files:


cat >.cvsignore <<EOF
error.log
*.structure
timed
tmp
EOF

cat >etc/.cvsignore <<EOF
status.*
*.counter
*.number
*.recordnumber
EOF

cat >products/.cvsignore <<EOF
*.lnk
*.sql
*.autonumber
*.[1-9]*
*.csv.numeric
*.name
*.sort
*.txt.*
EOF


echo "local.cfg" > config/.cvsignore
echo "*" > backup/.cvsignore
echo "*" > logs/.cvsignore
echo "*" > orders/.cvsignore
echo "*" > session/.cvsignore
echo "*" > upload/.cvsignore
echo "*" > tmp/.cvsignore

cvs add \
        .cvsignore \
        etc/.cvsignore \
        products/.cvsignore \
        config/.cvsignore \
        backup/.cvsignore \
        logs/.cvsignore \
        orders/.cvsignore \
        session/.cvsignore \
        upload/.cvsignore \
        tmp/.cvsignore \
        #done.


10.3. Mailserver for CVS updates

An easy alternative to setting up a mailserver is to merely alias the addresses that you would like updated. If you don't have many users following your commit list, it is recommended. In /etc/aliases, merely put:

 cvs-log:       address_one@yahoo.com,address_two@yahoo.com,address_three@yahoo.com

Then run newaliases and your "mini" mailing list will be all setup.

To setup a mailserver for CVS updates, first download and install Mailman. For RPM-based systems, check on rpmfind.net for a precompiled binary package.

After installing, read the following information about Mailman and what needs to be done after installation (taken from the RPM meta data):

"Mailman is software to help manage email discussion lists, much like Majordomo and Smartmail. Unlike most similar products, Mailman gives each mailing list a web page, and allows users to subscribe, unsubscribe, etc. over the web. Even the list manager can administer his or her list entirely from the web. Mailman also integrates most things people want to do with mailing lists, including archiving, mail <-> news gateways, and so on.

When the package has finished installing, you will need to:

  ScriptAlias /mailman/ /var/mailman/cgi-bin/
  Alias /pipermail/ /var/mailman/archives/public/
  <Directory /var/mailman/archives>
    Options +FollowSymlinks
  </Directory>

to /etc/httpd/conf/httpd.conf to configure your web server.

Users upgrading from previous releases of this package may need to move their data or adjust the configuration files to point to the locations where their data is."

Then run /var/mailman/bin/newlist and follow the directions from there.

10.4. Locally mapped source code for a network IC server

This is useful mostly to Windows users, since Linux users can just as easily run IC daemons on their own workstation as they can a separate server.

The idea is to have the IC server use its own files and directories for things that won't be edited and modified locally, but reference a Samba directory or NFS directory for things that will (such as pages/, templates/, etc.).

10.4.1. Mount the Samba or NFS directory

smbmount <...> or mount -t nfsfs <...>

The following script uses two directories (source and destination) to create symlinks for the commonly modified source directories of Interchange.

export S=/mnt/nfs/foundation
export D=/var/lib/interchange/foundation
F=db; ln -s $S/$F $D/$F
F=dbconf; ln -s $S/$F $D/$F
F=etc; ln -s $S/$F $D/$F
F=images; ln -s $S/$F $D/$F
F=pages; ln -s $S/$F $D/$F
F=special_pages; ln -s $S/$F $D/$F
F=templates; ln -s $S/$F $D/$F

This will leave you with a working catalog that can be quickly modified (since your editor can access the local copy), while Interchange has to do the work of going over the SMB or NFS connection.

10.5. jEdit - a good editor with Interchange/HTML/Perl colorization and CVS

I have been quite impressed with jEdit (http://www.jedit.org, and open source editor that is written in Java and runs on most platforms.

I use the interchange.xml language definition written by Chris Jesseman chris@sitemajic.net, which is available from http://www.sitemajic.net/jedit/. With this, jEdit automatically colors HTML, Perl, AND many Interchange tags very intelligently.

Further, jEdit has a CVS plugin, written by Ben Sarsgard bsarsgard@vmtllc.com, and available at: http://www.vmtllc.com/~bsarsgard/jedit.html. This plugin allows you to diff, update, and commit right from the editor.

10.6. Separate servers for development and live catalogs

If you have the luxury of separate server hardware for the development and live catalogs, you might find the following utility helpful:

It allows one to have a given CVS module automatically publish each update to an FTP server, which could serve as the live server. Or one could could use it if your CVS installation is only local and you could use it to upload your changes to your production server.

A. Credits

B. Document history

C. Resources

C.1. CVS Documentation

Here are some resources for learning more about CVS. I have ranked them by the order of usefulness, which is of course, objective.

C.2. CVS Server Software

C.3. CVS Client Software

There is a variety of client access methods for using CVS on your development box.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Dan Browning <dan.browning@kavod.com>. Freely redistributable under terms of the GNU General Public License. line:

Interchange + Forum/Blog HOWTO

11. Introduction

11.1. Preamble

Copyright 2002-2004 Mike Heins <mike.heins@perusion.net> and Michael Wilk <mwilk@steppenwolf.com>. Freely redistributable under terms of the GNU General Public License.

11.2. Purpose

The purpose of this document is to expose how to use Interchange 5.0's forum and blog capability, enabled with the [forum ...] tag and a few ancilliary files.

11.3. Audience

Anyone who is using an Interchange catalog. This is not rocket science.

11.4. Contact the authors

If you find any spelling errors, technical slip-ups, mistakes, subliminal messages, or if you wish to send feedback, critique, remarks, comments, or if you wish to contribute examples, instructions for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context diff against the SDF source file (ic_howto_forum.sdf). Please address your correspondence to:

Michael Wilk mwilk@steppenwolf.com

Mike Heins mike.heins@perusion.net

11.5. What it does

Interchange forums allow your customers to comment on your products, or allow you to sponsor discussion threads on an interchange catalog. They maintain their content in a single database table named forum.

12. Component files of the forums

There are two directories to add to your foundation catalog -- include/forum and pages/forum. You must add a database table definition, as well as a database source file. You should add Variable support to the variable.txt database, and supporting metadata with help. Finally, you need to add the forum.tag file which contains the forum code.

If you build a foundation catalog from the latest Interchange source, all of these will be done already.

The files that are needed in the catalog directory:

        dbconf/default_db/forum.dbm
        dbconf/mysql/forum.mysql
        dbconf/pgsql/forum.pgsql
        include/forum/reply_form
        include/forum/submit_form
        pages/forum/reply.html
        pages/forum/display.html
        pages/forum/submit.html
        products/forum.txt

The files that are needed in the Interchange software directory:

        code/UserTag/forum.tag

Add the following lines to products/variable.txt (change | to TAB):

FORUM_ANON_NAME|Anonymous Coward|Forums
FORUM_PRODUCTS|1|Forums
FORUM_EMAIL_NOTIFY|sales@yourcompany.com|Forums

Add the following records to products/mv_metadata.asc (shown in key: value format, edit file to match with "te" or some other tool):

#
# This is a temporary file, automatically generated from the
# database file:
#
# /tmp/what.txt
#
# If you change anything in it, it will be converted back into the
# original format and will replace the original file.
#
code:variable::Variable::FORUM_EMAIL_NOTIFY
type:text
width:50
height:
field:
db:
name:
outboard:
options:
attribute:
label:Forum notify email
help:An email address to send copies of user comments on products.
lookup:
filter:
help_url:
pre_filter:
lookup_exclude:
prepend:
append:
display_filter:
default:
extended:
#
code:variable::Variable::FORUM_ANON_NAME
type:text
width:20
height:
field:
db:
name:
outboard:
options:
attribute:
label:Forum Anonymous Name
help:Name to use when a user posts anonymously to a forum
lookup:
filter:
help_url:
pre_filter:
lookup_exclude:
prepend:
append:
display_filter:
default:
extended:
#
code:variable::Variable::FORUM_PRODUCTS
type:yesno
width:
height:
field:
db:
name:
outboard:
options:
attribute:
label:Enable Product Forums
help:This enables user comments on products in the flypage.
lookup:
filter:
help_url:
pre_filter:
lookup_exclude:
prepend:
append:
display_filter:
default:
extended:

Add the following block to pages/flypage.html:

        [if variable FORUM_PRODUCTS]
          <tr>
                <td>
                        [forum top="[item-code]" display_page="forum/display" /]
                        <p>
                        [page href="forum/reply"
                                        form="
                                                product=1
                                                mv_arg=[item-code]
                                        "
                        ]Comment on this product.</A>
                        </p>
                </td>
          </tr>
        [/if]

This would normally go at the end of the table displaying the product, but you can place and edit to suit.

Again, all of this is provided if you have installed from the latest Interchange 4.9.4 or higher.

13. The [forum] ITL Tag

The [forum] tag is what provides the capability. It uses the forum table and follows tree-like threads in that table.

It has one required parameter, top. That gives the id of the message that is the top of the thread to display.

This is a complete forum display for a product:

        [forum top="[item-code]" /]

You will see something like that in the snip from pages/flypage.html above.

You can pass many more parameters to the [forum] tag. Some of them are:

display-page

By default, the [forum ...] tag uses the current page to link to to re-display the forum at another level. Normally this works fine, but on a product flypage it will not work. You must pass in a different page.

        [forum top="[item-code]" display-page="forum/display" /]

show-level

By default, [forum] only displays the text of top-level replies to the current thread. If you want to display more levels, set the show-level parameter to 1 or higher:

        [forum top="[data session arg]" show-level=3 /]

The above will show the first four levels of replies, with links to any further down the tree.

scrub-score

If you want to moderate certain comments so that their text won't be shown, you can set the scrub-score parameter to -1 and then set the score field in the message's database record to -1. By default, it is linked to with a message:

  <A HREF="{DISPLAY_URL}">One message beneath your threshold</A>

If you want to totally disable the appearance of the link and message, set the scrub-template to something:

        [forum top=THREAD
                   scrub-score="-1"
               scrub-template="<!-- killed! -->"
        /]

show-score

By default, if a message has a score of two or higher, it's text will be shown no matter what level of display it is on. You can set that threshold with this paramter.

template

You can set the template that displays replies with this parameter. You can also pass this as the container text for the [forum] tag, i.e.:

        [forum top="[data session arg]"]
        <table cellspacing=0 cellpadding=2 width="65%">
                  <tr>
                        <td class=contentbar1>
                                <A HREF="{DISPLAY_URL}"><b>{SUBJECT}</b></A>
                                by <b>{USERINFO}</b>
                                on {DATE}
                        </td>
                        <td class=contentbar1 align=right>
                                &#91;
                                        <A HREF="{REPLY_URL}"><b>Reply</b></A>
                                &#93;
                        </td>
                  </tr>
                  <tr>
                        <td colspan=2>
                        {COMMENT}
                        </td>
                  </tr>
                </table>
        [/forum]

See pages/forum/display.html for an example.

header-template

You can set the header template that displays the top-level message with this parameter. See pages/forum/display.html for an example.

link-template

You can set the template that displays the links to messages that are not shown with this parameter. See pages/forum/display.html for an example.

scrub-template

The template for a message that has a score lower than scrub-score. See pages/forum/display.html for an example.

threshold-message

The message displayed in the default scrub-template when a message is scrubbed. If you set the scrub-template yourself, it is ignored.

display-page

The page linked to with {DISPLAY_URL}. Default is the current page. See Templating below.

reply-page

The page linked to with {REPLY_URL}. Default is forum/reply.html. See Templating below.

submit-page

The page linked to with {SUBMIT_URL}. Default is forum/submit.html. See Templating below.

date-format

The format for the date provided with {DATE}. Default is %B %e, %Y @%H:%M, which provides a date like October 5, 2002 @21:19.

14. Templating

All of the [forum] display mechanisms are templated. You can pass four templates -- template, header-template, link-template, and scrub-template.

They use the substitution style found in Interchange's attr-list ITL tag.

The following values are available for templating:

 ADDITIONAL    Additional text normally only used at the top level
 COMMENT       Text of the message
 CREATED       Created date in ISO format
 DATE          Date the comment was made
 DISPLAY_URL   URL to display the forum with a new starting point
 FORUM_APPEND  End indent </UL> tags for item (automatic, don't use)
 FORUM_PREPEND Begin indent <UL> tags for item (automatic, don't use)
 MOD_TIME      Modified date in ISO format
 PARENT_URL    URL to call the parent of the comment
 REASON        Text indicating reason for scoring
 REPLY_URL     URL to reply to the commetn
 SCORE         Score of the article
 SUBJECT       Subject of the message
 SUBMIT_URL    URL to submit a new top-level thread
 TOP_URL       URL to call the top level of the thread (if not at top)
 USERINFO      User information based on login status and anonymity

You can see how the above are used by examining the file pages/forum/display.html and playing around with the provided templates.

14.1. Templating rules

14.1.1. {KEY}

Inserts the value of the KEY for the reference. In a database query, this is the column name.

14.1.2. {KEY|fallback string}

Displays the value of {KEY} or if it is zero or blank, the fallback string (i.e., default).

14.1.3. {KEY true string}

Displays true string if the value of {KEY} is non-blank, non-zero, or displays nothing if the key is false.

14.1.4. {KEY?} true text {/KEY?}

Displays true text if the value of {KEY} is non-blank, non-zero, and nothing otherwise.

14.1.5. {KEY:} false text {/KEY:}

Displays false text if the value of {KEY} is blank or zero, and nothing otherwise.

Copyright 2002-2004 Mike Heins <mike.heins@perusion.net> and Michael Wilk <mwilk@steppenwolf.com>. Freely redistributable under terms of the GNU General Public License. line:

Interchange + QuickBooks HOWTO

15. Introduction

15.1. Summary Description

Interchange QuickBooks -- QuickBooks support for transactions and items

15.2. Audience

Users who already have Quickbooks setup and are familiar with it, in addition to having the foundation (or other) catalog correctly working.

15.3. Contact the author

If you find any spelling errors, technical slip-ups, mistakes, subliminal messages, or if you wish to send feedback, critique, remarks, comments, or if you wish to contribute examples, instructions for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context diff against the SDF source file (ic_howto_qb.sdf). Please address your correspondence to:

Volunteer Maintainer, Dan Browning db@kavod.com

or

Original Author, Mike Heins mike@perusion.com

15.4. Version

This document describes software based on Interchange 4.5 and later.

16. Description

Interchange is a business-to-business and business-to-consumer internet ordering and cataloguing product. It has the ability to take orders via the World Wide Web, and store transaction data.

This document describes how to interface Interchange with QuickBooks, the popular small-business accounting program from Intuit.

QuickBooks has an import/export format called IIF, a mnemonic for Intuit Interchange Format. Fitting, eh?

The standard capabilities of Interchange allow production of IIF files for transaction passing. With some support from Interchange UserTags, it can even import and export item listings.

17. Contents

The extension files can be found in the Interchange tarball under the 'extensions/quickbooks' directory. The following files are used with this extension:

  usertag/import_quicken_items  UserTag for importing items
  usertag/export_quicken_items  UserTag for exporting items
  pages/admin/quickbooks/*      Menu support for Interchange UI
  qb.catalog.cfg                Quickbooks configuration.

18. Installation

To set up this extension, the basic steps are:

18.1. Terms and locations

Several terms are used in the examples.

Catalog Directory

Interchange software directory

Interchange tarball directory

Interchange User

18.2. Create and copy directories and files

This extension requires you to add some files to your catalog.

It is assumed you have tools and knowledge to create directories with the proper permissions. Any directories that will contain varying files like order transaction logs will require write permission for the Interchange daemon user; pages and configuration only need have read permission.

18.3. Quick Installation Script

This script will install the necessary files for you, provided that you modify the variables to your environment. Alternately, you can follow the more detailed installation instructions that follow it.

Note that if you are not using a 4.9.8+ version of Interchange, you will need to manually install the qb_safe.filter by copying it from the 4.9.8 code/Filter/qb_safe.filter into your Interchange version.


# Modify these three variables to match your environment.
export QB=/path/to/interchange/extensions/quickbooks
export VENDROOT=/usr/local/interchange
export CATROOT=/home/interch/catalogs/foundation

mkdir -p $CATROOT/include/menus $CATROOT/vars
cp -r $QB/TRANS_QUICKBOOKS \
      $CATROOT/vars
cp -r $QB/pages/admin/quickbooks \
      $CATROOT/pages/admin
cp -i $QB/usertag/* \
      $VENDROOT/code/UI_Tag

# Alternate usertag installation style:
#
#mkdir -p $CATROOT/usertags/global
#cp -i $QB/usertag/* \
#      $CATROOT/usertags/global
#
# Then include the global/*.tag in your interchange.cfg

# Variables that optionally modify the export process, along with
# their help entries.
cat   $QB/products/variable.txt.append >> \
      $CATROOT/products/variable.txt
cat   $QB/products/mv_metadata.asc.append >> \
      $CATROOT/products/mv_metadata.asc

# Menu entries: start with the existing menu, then add ours.
cp -i $VENDROOT/lib/UI/pages/include/menus/Admin.txt \
      $CATROOT/include/menus
cat   $QB/menus/Admin.txt.append >> \
      $CATROOT/include/menus/Admin.txt

# Some configuration changes.
cat >> $CATROOT/catalog.cfg <<EOF
# Allows vars/TRANS_QUICKBOOKS
DirConfig vars
# You can remove these requires if you don't want to use the
# Quickbooks UI menu items
Require usertag import_quicken_items
Require usertag export_quicken_items
EOF

18.4. Admin UI Usage

After successful installation, there should be a "Quickbooks" menu item under the "Admin" category. From there, you can "generate IIF files", download them, and perform other Quickbooks-related tasks.

Make orders directory

Copy pages

Copy report generation file etc/trans_quickbooks

Copy usertags

18.5. Additional database fields -- userdb

If your catalog is not based on a 4.6+ version of the foundation catalog, you may not have some of the additional database fields necessary. If you want the user to retain their customer number, add the following field to the "userdb" table:

customer_number

It can be an integer number field if your database needs that information. To add the field in MySQL, you can issue the following queries at the mysql prompt:

alter table userdb add column customer_number int;

If you don't add it, it just means that a new customer number will be assigned every time.

WARNING If you are using Interchange DBM files and have live data it is not recommended you add this field unless you are positive you will not overwrite your data. If you are not a developer, get one to help you. In any case, back up your userdb.gdbm or userdb.db file first.

18.6. Additional database fields -- inventory

Quicken also needs an account to debit for the split transactions it uses to track item sales. If you don't create these fields to relate to each SKU, the account "Other Income" will be used in the exports.

Add the following fields to the "inventory" table:

account cogs_account

To add the fields in MySQL, you can issue the following queries at the mysql prompt:

alter table inventory add column account char(20); alter table inventory add column cogs_account char(20);

Other SQL databases will have similar facilities.

If you are using Interchange DBM files, just export the inventory database, stop the Interchange server (to prevent corruption), add the fields on the first line by editing the inventory.txt file, then restart Interchange.

18.7. Modify catalog.cfg with additions:

Add the entries in qb.catalog.cfg to catalog.cfg (you can use an include statement if you wish).

There are some Require directives to ensure that the needed UserTag definitions are included in the catalog, as well as the Route which is used

18.8. Add quickbooks order route

In the Interchange UI, there is a Preferences area "ORDER_ROUTES". You should add the quickbooks route. Place it after the transaction logging step, i.e.

code ORDER_ROUTES Variable log quickbooks main copy_user

ADVANCED, If you know Interchange Variable settings, you can add it directly:

Variable ORDER_ROUTES log quickbooks main copy_user

Also, you can use other methods to set order routes. See the Interchange reference documentation.

18.9. Additional Variables

Optionally, you may specify some variables that modify the behavior of the Quickbooks export feature. Documentation for these variables is provided via item-specific meta data, which can be added to your mv_metadata.asc file for automatic display by the Admin UI.

See the installation script at the top of this document for commands that will append the empty variables to your variable.txt and the help information to your mv_metadata.asc files.

18.10. Restart the catalog

This can be done by restarting the Interchange server or by clicking Apply Changes in the UI.

18.11. Export the items

You can access the Quickbooks UI index by making your URL:

http://YOURCATALOG_URL/admin/quickbooks/index

It will provide options for importing and exporting items. This is necessary so QuickBooks will be able to take orders for your items.

QuickBooks uses the product "name" as an SKU, along with an integer reference number. Either you need to make your SKUs match the integer reference number, or you must ensure your product title is unique.

18.12. Test

Place a test order on your Interchange catalog once you have finished installing. You should find a file in the orders directory with the name qbYYYYMMDD.iif. (YYYY=year, MM=month, DD=day.) Transfer this file to your QuickBooks machine and run File/Import and select that file as the source. This should import the customer and order into the system. If it doesn't work, it may be due to lack of sales tax or shipping definitions, discussed below.

19. Usage

19.1. Accessing Admin UI Features

A typical installation will cause the Administrative User Interface Features to become available via the top level menu:

You should then be presented with a menu of the Admin UI features.

19.2. Generating IIF Files

To generate the IIF files, access the corresponding page from the Admin UI Quickbooks Menu (Administration -> Quickbooks -> Generate IIF Files).

You will be presented with a query tool. Select the query options that you would like and submit your query. Among the query options, you have the option to input a QB transaction number. This will be the first number that is used when generating the IIF files, and it will be incremented for each sequential order in the query.

You will be notified of its success or failure. The resulting page will:

20. Discussion

The interface provided works for the sample company data distributed with QuickBooks. There are certain requirements to make sure it works in your environment.

Also, you can change the configuration by editing the file etc/trans_quickbooks to suit your IIF file needs.

20.1. Sales Tax

QuickBooks has a taxing system whereby tax rates are defined by customer location. There is usually also a generic Sales Tax Item, such as contained in the sample company data. This allows Interchange to calculate the sales tax. If that item is not present then you will need to create it, or specify your tax item using the QB_SALES_TAX_ITEM variable.

20.2. Shipping

Interchange will add a generic item Shipping to each order that has a shipping cost. Its MEMO field will contain the text description of the mode. If that item is not in your QuickBooks item definitions, then you must create it, or specify your shipping item using the QB_SHIPPING_ITEM variable.

20.3. Customer Imports

To generate a QuickBooks transtype of INVOICE, a CUSTOMER is required. Interchange outputs a CUST IIF record for each sale with the customer information. Since QuickBooks uses the customer name or company to generate the unique listing, we place the Interchange username in parentheses after the company or name.

20.4. IIF generation at time of order

As of 4.9, the IIF generation was moved from an order route into the Admin UI. This was done so that the IIF generation process could be fine tuned without restarting Interchange and placing an order. If you need the IIF file generated at the time of order, you can still access the pre-4.9.6 files in extensions/quickbooks/legacy.

D. Credits

E. Document history

F. Resources

F.1. Documentation

Copyright 2002-2004 Interchange Development Group. Freely redistributable under terms of the GNU General Public License. line:

Advanced Interchange Topics

21. Advanced Interchange Topics

22. Maintaining Interchange

Some utilities are supplied in the VendRoot/bin directory:

 compile_link Compiles an Interchange vlink or tlink CGI link
 configdump   Dumps the configuration directives for a particular catalog
 dump         Dumps the session file for a particular catalog
 expire       Expires sessions for a particular catalog
 expireall    Expires all catalogs
 makecat      Make catalog

Some example scripts for other functions are in the eg/ directory of the software distribution.

Some thought should be given to where the databases, error logs, and session files should be located, especially on an ISP that might have multiple users sharing an Interchange server. In particular, put all of the session files and logs in a directory that is not writable by the user. This eliminates the possibility that the catalog may crash if the directory or file is corrupted.

To test the format of user catalog configuration files before restarting the server, set (from VendRoot):

   bin/interchange -test

This will check all configuration files for syntax errors, which might otherwise prevent a catalog from booting. Once a catalog configures properly, user reconfiguration will not crash it. It will just cause an error. But, it must come up when the server is started.

22.1. Starting, Stopping, and Re-starting the Servers

The following commands need to have VENDROOT changed to the main directory where Interchange is installed. If the Interchange base directory is /home/interchange/, the start command would be /home/interchange/bin/interchange.

Do a perldoc VENDROOT/bin/interchange for full documentation.

To start the server with default settings:

   VENDROOT/bin/interchange

Assuming the server starts correctly, the names of catalogs as they are configured will be displayed, along with a message stating the process ID it is running under.

It is usually best to issue a restart instead. It doesn't hurt to do a restart if you're actually starting the first time. And, if a server is already running (from this VENDROOT), a new start attempt will fail. To restart the server:

   VENDROOT/bin/interchange -restart

The -r option is the same as -restart.

This is typically done to force Interchange to re-read its configuration. A message will be displayed stating that a TERM signal has been sent to the process ID the servers are running under. This information is also sent to VENDROOT/error.log. Check the error.log file for confirmation that the server has restarted properly.

To stop the server:

   VENDROOT/bin/interchange -stop

A message will be displayed stating that a TERM signal has been sent to the process ID the server is running under. This information is also sent to VENDROOT/error.log.

Because processes waiting for selection on some operating systems block signals, they may have to wait for HouseKeeping seconds to stop. The default is 60.

To terminate the Interchange server with prejudice, in the event it will not stop:

   VENDROOT/bin/interchange -kill

22.2. UNIX and INET modes

Both UNIX-domain and INET-domain sockets can be used for communication. INET domain sockets are useful when more than one web server, connected via a local-area network (LAN), is used for accessing an Interchange server.

Important note: When sending sensitive information like credit card numbers over a network, always ensure that the data is secured by a firewall, or that the Interchange server runs on the same machine as any SSL-based server used for encryption.

Use the -i and -u flags if you only want to use one communication method:

   # Start only in UNIX mode
   VENDROOT/bin/interchange -r -u

   # Start only in INET mode
   VENDROOT/bin/interchange -r -i

22.3. User Reconfiguration

The individual catalogs can be reconfigured by the user by running the [reconfig] support tag. This should be protected by one of the several forms of Interchange authentication, preferably by HTTP basic authorization. See RemoteUser.

The command line can be reconfigured (as the Interchange user) with:

   VENDROOT/bin/interchange --reconfig=catalog

It is easy for the administrator to manually reconfigure a catalog. Interchange simply looks for a file etc/reconfig (based in the Interchange software directory) at HouseKeeping time. If it finds a script name that matches one of the catalogs, it will reconfigure that catalog.

22.4. Expiring Sessions

If Interchange is using DBM capability to store the sessions, periodically expire old sessions to keep the session database file from growing too large.

   expire -c catalog

There is also an expireall script which reads all catalog entries in interchange.cfg and runs expire on them. The expire script accepts a -r option which tells it to recover lost disk space.

On a UNIX server, add a crontab entry such as the following:

   # once a day at 4:40 am
   40 4 * * *    perl /home/interchange/bin/expireall -r

Interchange will wait until the current transaction is finished before expiring, so this can be done at any time without disabling web access. Any search paging files for the affected session (kept in ScratchDir) will be removed as well.

If not running DBM sessions, use a Perl script to delete all files not modified in the last one or two days. The following will work if given an argument of a session directory or session files:

   #!perl
   # expire_sessions.pl -- delete files 2 days old or older

   my @files;
   my $dir;
   foreach $dir (@ARGV) {
       # just push files on the list
       if (-f $dir) { push @files, $_; next; }

       next unless -d $dir;

       # get all the file names in the directory
       opendir DIR, $dir or die "opendir $dir: $!\n";
       push @files, ( map { "$dir/$_" } grep(! /^\.\.?$/, readdir DIR));
   }

   for (@files) {
       unless (-f $_) {
           warn "skipping $_, not a file.\n";
           next;
       }
       next unless -M $_ >= 2;
       unlink $_ or die "unlink $_: $!\n";
   }

It would be run with a command invocation like:

   perl expire_sessions.pl /home/you/catalogs/simple/session

Multiple directory names are acceptable, if there is more than one catalog.

This script can be adjusted as necessary. Refinements might include reading the file to "eval" the session reference and expire only customers who are not members.

22.5. My session files change to owner root every day!

You have the expireall -r entry in the root crontab, and it should either be in the Interchange user crontab or run as:

44 4 * * * su -c "/ICROOT/bin/expireall -r" ICUSERNAME

23. Interchange Components

Interchange components are merely portions of HTML/ITL that are included into pages within the site depending on options set in the Admin UI. The default component set includes the following:

best_horizontal
best_vertical
cart
cart_display
cart_tiny
category_vertical
cross_horizontal
cross_vertical
promo_horizontal
promo_vertical
random_horizontal
random_vertical
upsell_horizontal
upsell_vertical

23.1. Content -> Page Edit

The Interchange Admin UI offers a page editor function that allows component definitions and options to be modified for each page within the catalog.

23.1.1. Template

The choices for the Template drop-down are read from template definition files located in the CATROOT/template directory. These files store the name and description of the template, as well as components and options for the particular template.

To create a new template for use in the admin, it is best to copy an existing template definition to a new file name and edit it's contents to suit. Once the catalog is reconfigured, the new choice will be visible within the Content Page Editor admin function.

Each template option is looped through and a scratch is set using its same name and value.

ITL is used near the bottom of this file to set each option to default values before the page is displayed.

[set page_title][set]
[set page_banner][set]
[set members_only][set]
[set component_before][set]
[set component_after][set]
[set bgcolor]#FFFFFF[/set]

23.1.2. Page Title

Sets the title of the page which is synonymous with the html <title></title> code.

The following code within the template definition file is used to display this option within in the content editor:

page_title: description: Page title

This code dynamically adds the title to the page:

<title>[scratch page_title]</title>

23.1.3. Page Banner

Sets a textual title for each page which is called by [either][scratch page_banner][or][scratch page_title][/either] This results in the Page Banner being displayed if defined. Otherwise, the Page Title is used.

23.1.4. Members Only

The members only function is handled by the following code within each template file:

[if scratch members_only]
    [set members_only][/set]
    [if !session logged_in]
    [set mv_successpage]@@MV_PAGE@@[/set]
    [bounce page=login]
    [/if]
[/if]

This code says if members only is set to yes and the visitor is logged in, display the page. Otherwise, redirect the visitor to the login page.

23.1.5. Break 1

This code causes a separation in the Content Editor between the next set of options. (A blue line)

23.1.6. Horizontal Before Component

This allows the inclusion of a defined component to be displayed before, or above, the page's content. It is called with the following code within the LEFTRIGHT_TOP template:

[if scratch component_before]
[include file="templates/components/[scratch component_before]"]
[set component_before][/set]
[/if]

23.1.7. Horizontal After Component

This function allows the inclusion of a defined component to be displayed after or below the page's content. It's called with the following code within the LEFTRIGHT_BOTTOM template:

[if scratch component_after]
[include file="templates/components/[scratch component_after]"]
[set component_after][/set]
[/if]

23.1.8. Horizontal Item Width

This setting allows you to choose how many items the horizontal components display. For example, the horizontal best sellers component uses this setting to randomly select the best sellers. Notice the default to 2 if nothing is defined.

random="[either][scratch component_hsize][or]2[/either]"

23.1.9. Special Tag

This setting is only viable when a promotion is used for a horizontal component. It tells the promotional component which rows to evaluate in the merchandising table for display within the component. This setting normally correlates to the featured column of the merchandising table as follows:

        [query arrayref=main
                           sql="
                                SELECT sku,timed_promotion,start_date,finish_date
                                FROM merchandising
                                WHERE featured = '[scratch hpromo_type]'
                           "][/query]

23.1.10. Before/After Banner

Allows a title for the horizontal components to be defined to displayed in a header above the component's items. It is called with the [scratch hbanner] tag.

23.1.11. Break 2

This code causes a separation in the Content Editor between the next set of options. (A blue line)

23.1.12. Vertical Component

Defines a component to be displayed along the right side of the LEFTRIGHT_BOTTOM template. It is called from the template with the following code:

[include file="templates/components/[scratch component_right]"]

23.1.13. Vertical Items Height

Sets the number of items to display within the vertical component. Called with the following code:

random="[either][scratch component_vsize][or]3[/either]"

23.1.14. Right Banner

Allows a title to be set for a vertical component which is displayed as a header above the items in the vertical component. It's called with the [scratch vbanner] tag.

23.1.15. Special Tag

Essentially the same as the Special Tag setting described in item number 9 above.

23.1.16. Background Color

Allows the background color of the page to be selected. The choices are stored within the page or template definition as in:

bgcolor:
        options: #FFFFFF=White,pink=Pink
        widget: select
        description: Background color

23.1.17. Content

Allows the page code to be downloaded, uploaded and viewed/edited. Only the code between <!-- BEGIN CONTENT --> and <!-- END CONTENT --> is displayed or can be edited here.

23.1.18. Preview, Save, and Cancel buttons

Allows the changes to the edited page to be previewed in a pop-up browser window, or saved. Cancel returns you to the page editor selection page.

23.1.19. Save template in page

Template settings are stored in the template definitions by default. This allows a common set of choices for template settings for all pages. If specific setting options are desired for a page, the template can be saved within the page so that it may have individual options.

The in-page template definition must be surrounded by [comment] [/comment].

23.2. Custom Admin UI Options

Other options may be added to the template by defining them in the default definition file, or using in-page definitions.

When the following lines are added to the template definition, the new option is added to the Admin UI.

option_name:
options: 1,2*,3
widget: select
description: Option Description
help: Other Details

Each time the template is used, an option_name scratch variable is created. (Called with: [scratch option_name].) This scratch value will be equal to what's selected here in the admin tool.

The possible widgets include:

break - produces the blue line separator.
radio - produces radio button type selections.
select - standard drop-down selector.
move_combo - select drop down with options and text input for new option.

24. Administrative Pages

With Interchange's GlobalSub capability, very complex add-on schemes can be implemented with Perl subroutines. And with the new writable database, pages that modify the catalog data can be made. See MasterHost, RemoteUser, and Password.

In addition, any Interchange page subdirectory can be protected from access by anyone except the administrator if a file called '.access' is present and non-zero in size.

24.1. Controlling Access to Certain Pages

If the directory containing the page has a file .access and that file's size is zero bytes, access can be gated in one of several ways.

  1. If the file .access_gate is present, it will be read and scanned for page-based access. The file has the form:
  page: condition
  *: condition
 -rw-rw-r--   1 mike     mike            0 Jan  8 14:19 .access
 -rw-rw-r--   1 mike     mike          185 Jan  8 16:00 .access_gate
 -rw-rw-r--   1 mike     mike          121 Jan  8 14:59 any.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 bar.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 baz.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 foo.html
   foo.html: [if session username eq 'flycat']
               Yes
             [/if]
   bar:      [if session username eq 'flycat']
             [or scratch allow_bar]
               Yes
             [/if]
   baz:      yes
   *:        [data session logged_in]
  1. If the Variable MV_USERDB_REMOTE_USER is set (non-zero and non-blank), any user logged in via the UserDB feature will receive access to all pages in the directory. NOTE: If there is a .access_gate file, it overrides this.
  2. If the variables MV_USERDB_ACL_TABLE is set to a valid database identifier, the UserDB module can control access with simple ACL logic. See USER DATABASE. NOTE: If there is a .access_gate file, it overrides this. Also, if MV_USERDB_REMOTE_USER is set, this capability is not available.

24.2. display tag and mv_metadata

Interchange can store meta information for selected columns of tables in a site's database. This meta information is used when the user interacts with the database. For example, the meta information for a Hide Item field might specify that a checkbox be displayed when the user edits that field, since the only reasonable values are on and off. Or, the meta information might specify a filter on data entered for a Filename field which makes sure that the characters entered are safe for use in a filename.

Widget type specifies the HTML INPUT tag type to use when displaying the field in, say, the item editor.

Width and Height only apply to some of the Widget type options, for instance the Textarea widget.

Label is displayed instead of the internal column name. For example, the category column of the products table might have a label of Product Category.

Help is displayed below the column label, and helps describe the purpose of the field to the user.

Help url can be used to link to a page giving more information on the field.

Lookup can be used when a field is acting like a foreign key into another table. In that case, use some sort of select box as the widget type, and if referencing multiple rows in the destination table, use a multi select box, with colons_to_null as the pre_filter, and :: as the lookup_exclude.

Filter and pre_filter can be used to filter data destined for that field or data read from that field, respectively.

Repeat?: The Interchange back office UI uses the mv_metadata table to discover formatting information for field, table, and view display. The information is kept in fields in the mv_metadata table, and is used to select the display, the HTML input type, the size (height and width where appropriate), label, help text, additional help URL, and default value display.

It works in conjunction with the [display ...] usertag defined in the Interchange UI as well as in specific pages in the UI. The [display] tag has this syntax:

[display table=tablename column=fieldname key=key arbitrary=tag filter=op ...]

In the simplest use, the formatting information for a table form field is called with:

The mv_metadata table is scanned for the following keys:

 products::category::os28007
 products::category

If a row is found with one of those keys, then the information in the row is used to set the display widget. If no row is found, an INPUT TYPE=TEXT widget is displayed. If the data is all digits, a size of 8 is used, otherwise the size is 60.

If the following row were found (not all fields shown, would be tab-separated in the actual data):

  code                type   width height label     options
  products::category  text   20           Category

Then this would be output:

<INPUT TYPE=text SIZE=20 VALUE="*category*">

If the following row were found:

  code                type   width height label     options
  products::category  select              Category  =none, product=Hardware

Then the following would be output:

        <SELECT NAME=category>
        <OPTION VALUE="">none
        <OPTION VALUE="product">Hardware
        </SELECT>

The standard widget types are:

text

    width   size of input box

textarea

        width   COLS for textarea
        height  ROWS for textarea

select

  height          SIZE for select
  default         Default for SELECTED
  options         Options for a fixed list (or prepended to a lookup)
  lookup          signals a lookup (used as field name if "field" empty)
  field           field to look up possible values in
  db              table to look up in if not current table
  lookup_exclude  regular expression to exclude certain values from lookup

25. Usertag Reference

Admin Tool-specific usertags.

26. Admin Tool Database Tables

26.1. mv_metadata.asc

    code
        Table::Column to be operated on.
        Database table
    type
        Widget type (Select the basic display type for the field)
            textarea = Textarea
            text = Text Entry (default)
            select = Select Box
            yesno = Yes/No (Yes=1)
            noyes = No/Yes (No=1)
            multiple = Multiple Select
            combo = Combo Select
            reverse_combo = Reverse Combo
            move_combo = Combo move
            display = Text of option
            hidden_text = Hidden(show text)
            radio = Radio box
            radio_nbsp = Radio (nbsp)
            checkbox = Checkbox
            check_nbsp = Checkbox (nbsp)
            imagedir = Image listing
            imagehelper = Image upload
            date = Date selector
            value = Value
            option_format = Option formatter
            show = Show all options
    width
        Width (SIZE for TEXT, COLS for TEXTAREA, Label limit for SELECT)
    height
        Height (SIZE for SELECT, ROWS for TEXTAREA)
    field
        Field for lookup (can be two comma separated fields, in which
        case second is used as the label text. Both must be in the
        same table.)
    db
    name
        Variable name (normally left empty, changes variable name to
        send in form)
    outboard
        Select directory for image listing widget
    options
        options in the format <blockquote>value=label*</blockquote>
    attribute
        Column name (Do not set this.)
    label
    help
        Help (displays at top of page)
    lookup
        Lookup select (Whether lookup is performed to get options for a
        select type. If nothing is in the field, then used as the name
        of the field to lookup in. Use lookup table if you want to look
        up in a different table.
    filter
        Filters (Filters which can transform or constrain your data.
        Some widgets require filters.)
    help_url
        Help URL (links below help text)
        A URL which will provide more help
    pre_filter
    lookup_exclude
        ADVANCED: regular expression that excludes certain keys from the lookup
    prepend
    append
        Append HTML (HTML to be appended to the widget. Will substitute
        in the macros _UI_TABLE_, _UI_COLUMN_, _UI_KEY_, and _UI_VALUE_,
        and will resolve relative links with absolute links.)
    display_filter

27. makecat - Set Up a Catalog from a Template

After Interchange is installed, you need to set up at least one catalog. Interchange will not function properly until a catalog is created.

The supplied makecat script, which is in the Interchange program directory bin, is designed to set up a catalog based on the user's server configuration. It interrogates the user for parameters like which directories to use, a URL to base the catalog in, HTTP server definitions, and file ownership. It gives relevant examples of the entries it expects to receive.


Note: A catalog can only be created once. All further configuration is done by editing the files within the catalog directory.

The makecat script requires a catalog skeleton to work from. The Foundation demo is distributed with Interchange. See the icfoundation document for information on building the Foundation demo store. Other demo catalogs are available at http://www.icdevgroup.org/.

It is not normally necessary for you to understand how to build catalog skeletons for use with makecat, but the following information will help you if you should ever need to.

27.1. Catalog Skeletons

A catalog skeleton contains an image of a configured catalog. The best way to see what the makecat program does is to configure the simple demo and then run a recursive diff on the template and configured catalog directories:

    cd /usr/local/interchange
    diff -r construct catalogs/construct

The files are mostly identical, except that certain macro strings have been replaced with the answers given to the script. For example, if www.mydomain.com was answered at the prompt for a server name, this difference would appear in the catalog.cfg file:

    # template
    Variable SERVER_NAME  __MVC_SERVERNAME__

    # configured catalog
    Variable SERVER_NAME  www.mydomain.com

The macro string __MVC_SERVERNAME__ was substituted with the answer to the question about server name. In the same way, other variables are substituted, and include:

    MVC_BASEDIR      MVC_IMAGEDIR
    MVC_CATROOT      MVC_IMAGEURL
    MVC_CATUSER      MVC_MAILORDERTO
    MVC_CGIBASE      MVC_MINIVENDGROUP
    MVC_CGIDIR       MVC_MINIVENDUSER
    MVC_CGIURL       MVC_SAMPLEHTML
    MVC_DEMOTYPE     MVC_SAMPLEURL
    MVC_DOCUMENTROOT MVC_VENDROOT
    MVC_ENCRYPTOR


Note: Not all of these variables are present in the "construct" template, and more may be defined. In fact, any environment variable that is set and begins with MVC_ will be substituted for by the makecat script. For example, to set up a configurable parameter to customize the COMPANY variable in catalog.cfg, run a pre-qualifying script that set the environment variable MVC_COMPANY and then place in the catalog.cfg file:

Variable COMPANY __MVC_COMPANY__

All files within a template directory are substituted for macros, not just the catalog.cfg file. There are two special directories named html and images. These will be recursively copied to the directories defined as SampleHTML and ImageDir.


Note: The template directory is located in the Interchange software directory, i.e., where interchange.cfg resides. Avoid editing files in the template directory. To create a new template, it is recommended that it should be named something besides 'construct' and a copy of the construct demo directory be used as a starting point. Templates are normally placed in the Interchange base directory, but can be located anywhere. The script will prompt for the location if it cannot find a template.

In addition to the standard parameters prompted for by Interchange, and the standard catalog creation procedure, four other files in the config directory of the template may be defined:

 additional_fields -- file with more parameters for macro substitution
 additional_help   -- extended description for the additional_fields
 precopy_commands  -- commands passed to the system prior to catalog copy
 postcopy_commands -- commands passed to the system after catalog copy

All files are paragraph-based. In other words, a blank line (with no spaces) terminates the individual setting.

27.1.1. Additional fields

The additional_fields file contains:

    PARAM
    The prompt. Set PARAM to?
    The default value of PARAM^IAlternate value of PARAM

This would cause a question during makecat:

    The prompt. Set PARAM to?.....[The default value of PARAM]

The default value line can contain alternate values, separated by tabs from the default value. (The default value may not contain a TAB character.) This will allow command-line editing to cycle between the different values -- usually with the UP and DOWN arrow keys.

If you wish to set the parameter to the default value in this file without a prompt, precede the parameter with an exclamation point, i.e.:

    !PARAM
    The prompt.  Set PARAM to?
    default value^Ialternate value

If you wish only to prompt for a value if a previous parameter was set, put the previous parameter to set in curly brackets before the actual parameter:

    {MYSQL}SQLDSN
    Data source name (DSN) for MySQL?
    dbi:mysql:test___MVC_CATALOGNAME__

The above will be ignored if the MYSQL parameter was not previously set to a true value.

Note that information collected in the main makecat run (in this case, the catalog name) can be inserted via macro substitution.

27.1.2. Additional help

If the additional_help file is present, additional instructions for PARAM may be provided.

    PARAM

    These are additional instructions for PARAM, and they
    may span multiple lines up to the first blank line.

The prompt would now be:

    These are additional instructions for PARAM, and they
    may span multiple lines up to the first blank line.

    The prompt. Set PARAM to?.....[The default value of PARAM]

27.1.3. Command files

If the file config/precopy_commands exists, it will be read as a command followed by the prompt/help value.

    mysqladmin create __MVC_CATALOGNAME__
    We need to create an SQL database for your Interchange
    database tables.

This will cause the prompt:

    We need to create an SQL database for your Interchange
    database tables.

    Run command "mysqladmin create simple"?

If the response is "y" or "yes," the command will be run by passing it through the Perl system() function. As with any of the additional configuration files, MVC_PARAM macro substitution is performed on the command and help. Proper permissions for the command are required.

The file config/postcopy_commands is exactly the same as <precopy_commands>, except the prompt occurs after the catalog files are copied and macro substitution is performed on all files.

There may also be SubCatalog directives:

    SubCatalog easy simple /home/catalogs/simple /cgi-bin/easy

easy

simple

The remaining parameters are similar to the Catalog directive.

Additional interchange.cfg parameters set up administrative parameters that are catalog wide. See the server configuration file for details on each of these.

Each catalog can be completely independent with different databases, or catalogs can share pages, databases, and session files. This means that several catalogs can share the same information, allowing "virtual malls."

27.2. Manual Installation of Catalogs

An Interchange installation is complex, and requires quite a few distinct steps. Normally you will want to use the interactive catalog builder, makecat, described above. It makes the process much easier. Please see the iccattut document for a full tutorial on building a catalog by hand.

28. Link Programs

Interchange requires a web server that is already installed on a system. It does have an internal server which can be used for administration, testing, and maintenance, but this will not be useful or desirable in a production environment.

As detailed previously, Interchange is always running in the background as a daemon, or resident program. It monitors either a UNIX-domain file-based socket or a series of INET-domain sockets. The small CGI link program, called in the demo simple, is run to connect to one of those sockets and provide the link to a browser.


Note: Since Apache is the most popular web server, these instructions will focus on it. If using another type of web server, some translation of terms may be necessary.

A ScriptAlias or other CGI execution capability is needed to use the link program. (The default ScriptAlias for many web servers is /cgi-bin.) If ExecCGI is set for all directories, then any program ending in a particular file suffix (usually .cgi) will be seen as a CGI program.

Interchange, by convention, names the link program the same name as the catalog ID, though this is not required. In the distribution demo, this would yield a program name or SCRIPT_PATH of /cgi-bin/simple or /simple.cgi. This SCRIPT_PATH can be used to determine which Interchange catalog will be used when the link program is accessed.

28.1. UNIX-Domain Sockets

This is a socket which is not reachable from the Internet directly, but which must come from a request on the server. The link program vlink is the provided facility for such communication with Interchange. This is the most secure way to run a catalog, for there is no way for systems on the Internet to interact with Interchange except through its link program.

The most important issue with UNIX-domain sockets on Interchange is the permissions with which the CGI program and the Interchange server run. To improve security, Interchange normally runs with the socket file having 0600 permissions (rw-------), which mandates that the CGI program and the server run as the same user ID. This means that the vlink program must be SUID to the same user ID as the server executes under. (Or that CGIWRAP is used on a single catalog system).

With Interchange's multiple catalog capability, the permissions situation gets a bit tricky. Interchange comes with a program, makecat, which configures catalogs for a multiple catalog system. It should properly set up ownership and permissions for multiple users if run as the superuser.

28.2. INET-Domain Sockets

These are sockets which are reachable from the Internet directly. The link program tlink is the provided facility for such communication with Interchange. Other browsers can talk to the socket directly if mapped to a catalog with the global TcpMap directive. To improve security, Interchange usually checks that the request comes from one of a limited number of systems, defined in the global TcpHost directive. (This check is not made for the internal HTTP server.)

28.3. Internal HTTP Server

If the socket is contacted directly (only for INET-domain sockets), Interchange will perform the HTTP server function itself, talking directly to the browser. It can monitor any number of ports and map them to a particular catalog. By default, it only maps the special catalog mv_admin, which performs administrative functions. The default port is 7786, which is the default compiled into the distribution tlink program. This port can be changed via the TcpMap directive.

To prevent catalogs that do not wish access to be made in this way from being served from the internal server, Interchange has a fixed SCRIPT_PATH of /catalogname (/simple for the distribution demo) which needs to be placed as an alias in the Catalog directive to enable access. See TcpMap for more details.

28.4. Setting Up VLINK and TLINK

The vlink and tlink programs, compiled from vlink.c and tlink.c, are small C programs which contact and interface to a running Interchange daemon. The VLINK executable is normally made setuid to the user account which runs Interchange, so that the UNIX-domain socket file can be set to secure permissions (user read-write only). It is normally not necessary for the user to do anything. They will be compiled by the configuration program. If the Interchange daemon is not running, either of the programs will display a message indicating that the server is not available. The following defines in the produced config.h should be set:

LINK_FILE

LINK_HOST

LINK_PORT

LINK_TIMEOUT

28.5. Compiling VLINK and TLINK

There is a compile_link program which will assist with this. Do:

   perldoc VENDROOT/bin/compile_link

for its documentation.

28.6. Manually Compiling VLINK and TLINK

Change directories to the src directory, then run the GNU configure script:

   cd src
   ./configure

There will be some output displayed as the configure script checks the system. Then, compile the programs:

   perl compile.pl

To compile manually:

   cc vlink.c -o vlink
   cc tlink.c -o tlink

On manual compiles, ensure that the C compiler will be invoked properly with this little ditty:

   perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o tlink tlink.c");'
   perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o vlink vlink.c");'

On some systems, the executable can be made smaller with the strip program, if available. It is not required.

   strip vlink
   strip tlink

If Interchange is to run under a different user account than the individual configuring the program, make that user the owner of vlink. Do not make vlink owned by root, because making vlink SETUID root is an huge and unnecessary security risk. It should also not normally run as the default Web user (often nobody or http)).

   chown interchange vlink

Move the vlink executable to the cgi-bin directory:

   mv vlink /the/cgi-bin/directory

Make vlink SETUID:

   chmod u+s /the/cgi-bin/directory/vlink

Most systems unset the SUID bit when moving the file, so change it after moving.

The SCRIPT_NAME, as produced by the HTTP server, must match the name of the program. (As usual, let the makecat program do the work.)

28.7. VLINK or TLINK Compile Problems

The latest version of vlink.c and tlink.c have been compiled on the following systems:

   AIX 4.1
   BSD2.0 (Pentium/x86)
   Debian GNU/Linux
   Digital Unix (OSF/Alpha)
   FreeBSD 2.x, 3.x, 4.x
   IRIX 5.3, IRIX 6.1
   OpenBSD 2.7
   Red Hat Linux 6.2, 7.0, 7.1, 7.2, 7.3, 8.0
   SCO OpenServer 5.x
   Solaris 2.x (Sun compiler and GCC)
   Solaris 7 (Sun compiler and GCC)
   SunOS 4.1.4

Some problems may occur. In general, ignore warnings about pointers.

Make sure that you have run the configure program in the src directory. If you use Interchange's makecat program, it will try to compile an appropriate link at that time, and will substitute tlink.pl if that doesn't work.

You can compile manually with the proper settings with this series of commands:

   cd src
   ./configure
   perl -e 'do "syscfg"; system ("$CC $CFLAGS $DEFS $LIBS -o tlink tlink.c")'
   perl -e 'do "syscfg"; system ("$CC $CFLAGS $DEFS $LIBS -o vlink vlink.c")'

There is also a compile_link program which has documentation embedded and which will compile an appropriate link. If you cannot compile, try using the tlink.pl script, written in Perl instead of C, which should work on most any system. Since vlink needs to have values set before compilation, a pre-compiled version will not work unless it has the exact values you need on your system. If you can use the defaults of 'localhost' and port 7786, you may be in luck.

29. Installing Perl Modules without Root Access

Installing Interchange without root access is no problem. However, installing Perl modules without root access is a little trickier.

You must build your makefile to work in your home dir. Something like:

PREFIX=~/usr/local \
INSTALLPRIVLIB=~/usr/local/lib/perl5 \
INSTALLSCRIPT=~/usr/local/bin \
INSTALLSITELIB=~/usr/local/lib/perl5/site_perl \
INSTALLBIN=~/usr/local/bin \
INSTALLMAN1DIR=~/usr/local/lib/perl5/man \
INSTALLMAN3DIR=~/usr/local/lib/perl5/man/man3

Put this in a file, say 'installopts', and use it for the Makefile.PL.

perl Makefile.PL `cat installopts`

Then, forget ./config. Just do:

make
make test
make install

Some of the tests may fail, but that's probably ok.

Also make sure to install Bundle::Interchange, which will need the same config data as you put into 'installopts'.

30. Installation Troubleshooting

Interchange uses the services of other complex programs, such as Perl, Web servers, and relational databases, to work. Therefore, when there is a problem, check these programs before checking Interchange. Many more basic installation problems have to do with those than with Interchange itself.

If an error message is received about not being able to find libraries, or a core dump has occurred, or a segment fault message, it is always an improperly built or configured Perl. Contact the system administrator or install a new Perl.

The makecat program is intended to be used to create the starting point for the catalog. If the demo does not work the first time, keep trying. If it still does not work, try running in INET mode.

Check the two error log files: error.log in the Interchange home directory (where interchange.cfg resides) and error.log in the catalog directory (where catalog.cfg resides; there can be many of these). Many problems can be diagnosed quickly if these error logs are consulted.

Check the README file, the FAQ, and mail list archive at the official Interchange web site for information:

       http://www.icdevgroup.org/

Double check the following items:

  1. Using UNIX sockets?
    • Check that the vlink program is SUID, or the appropriate changes have been made in the SocketPerms directive. Unless the files are world-writable, the vlink program and the Interchange server must run as the same user ID! If running CGI-WRAP or SUEXEC, the vlink program must not be SUID.
    • If having trouble with the vlink program (named construct in the demo configuration), try re-running makecat and using INET mode instead. (Or copy the tlink INET mode link program over vlink). This should work unchanged for many systems.
    • If using an ISP or have a non-standard network configuration, some changes to interchange.cfg are necessary. For tlink to work, the proper host name(s) must be configured into the TcpHost directive in interchange.cfg. The program selects port 7786 by default (the ASCII codes for "M" and "V", for MiniVend). If another port is used, it must be set to the same number in both the tlink program (by running compile_link) and the interchange.cfg file. The tlink program does not need to be SUID.
  2. Proper file permissions?
    • The Interchange server should not run as the user nobody! The program files can be owned by anyone, but any databases, ASCII database source files, error logs, and the directory that holds them must be writable by the proper user ID, that is the one that is executing the Interchange program.
    • The best way to operate in multi-user, multiple catalog setups is to create a special interch user, then put that user in the group that contains each catalog user. If a group is defined for each individual user, this provides the best security. All associated files can be in 660 or 770 mode. There should be no problems with permissions and no problems with security.
  3. Is the vlink program being executed on a machine that has the socket file etc/socket on a directly attached disk?
    • UNIX-domain sockets will not work on NFS-mounted file systems! This means that the Interchange server and the CGI program vlink must be executing on the same machine.
    • The tlink program does not have this problem, but it must have the proper host name(s) and TCP ports set in the TcpHost and TcpMap directives in interchange.cfg. Also, be careful of security if sensitive information, like customer credit card numbers, is being placed on a network wire.

31. Usertracking

Several actions from the user are recorded by Interchange's usertracking facility. The usertracking data is logged at two locations, depending on your setup.

The first location is the one specified by the TrackFile configuration directive, e.g. logs/usertrack in the foundation demo.

The second location are the HTTP headers. You can configure Apache to write this header into the access logs.

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \
                        %T %v \"%{X-Track}o\"" track
CustomLog /var/log/apache/access.log track

Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Catalog-Building Tutorial

32. Purpose

The purpose of this document is to guide you through constructing a simple Interchange catalog from scratch. The demo catalog that ships with Interchange is quite complex since it highlights some of the many capabilities that Interchange offers. As a template for your own catalog, the demo can be an intimidating place to start if your purpose is to learn.

The simple catalog you create using this tutorial should give you a feel for the basic Interchange system. It should also be considered a stepping stone to a more complete and functional e-commerce system built with Interchange. The tutorial relies as much as possible on default settings to accentuate how Interchange works. It will use as few of Interchange's capabilities as possible, while still building a usable store. The resulting site will be simple but usable. The value of this tutorial is in the instruction that occurs along the way.

It is recommended that you create the files used in this tutorial yourself. You will learn more by creating the directory structure and using your favorite text editor to create files in the proper places on your own system as they are discussed.

33. Before you begin

This section explains the initial set up tasks that must be completed before you can begin building your simple e-commerce site.

33.1. Install Interchange and the demo catalog

The easiest way to get Interchange and the demo set up is through an RPM install on the Red Hat Linux or Linux Mandrake operating systems. You can also get Interchange by unpacking an Interchange tarball or checking out a copy of the CVS repository and doing a manual installation. These installations can be done either as a regular user or as root, installing for a special Interchange user.

You must also know what type of installation you ran so you know where to place the various files created. Before proceeding, verify that Interchange is properly installed. Also, keep in mind which type of installation you did:


Note: After installation, makecat should be run to build your catalog. For information on installing Interchange and building your catalog using makecat, see the Interchange Getting Started Guide. Do not to continue with this tutorial without a working demo catalog.

Installing the demo catalog set up the Interchange global configuration file interchange.cfg, which resides in the Interchange software directory. Also, it compiled the link program for your specific server and placed the executable program in your cgi-bin directory. This is necessary for your catalog to run properly.

33.2. The Interchange operating system user

If Interchange was installed as a regular user, that will be the user Interchange runs as. If Interchange was installed as root or from an RPM, you need to know the name of the separate Interchange user. The Interchange daemon will not run as root, and should not run as the web server user (usually 'apache', 'www', 'httpd', or 'nobody'). If Interchange was installed from the RPM, or with the default source installation settings, the username is interch. If you selected a different user name, you will need to know what it is.

33.3. Important directories

In order to complete this tutorial you will need to know the location of each of the following directories and have write permissions on them:


Note: The installation of Interchange is very flexible and the file locations on your system may vary, depending on how your system was set up. It is recommended that you not proceed until you are sure you have this information and the necessary permissions to write to these directories.

33.4. Your catalog URL

Finally, you need to know the URL to access your store from a web browser. Again, this can vary depending on how your web server has been set up. But, assuming a common setup of the Apache web server, your URL should be one of the following:

If you aren't running your web browser on the server where Interchange is running, you need to substitute your server's host name (for example: machine.domain.com for localhost) where mentioned.


Note: It is recommended that you use the real machine name instead of localhost. The standard for cookies specifies that they can only be set when a domain name has at least two dots in it. If you use localhost, you will lose session information if you leave catalog, since the session ID is passed only as part of the URL.

33.5. Starting or restarting Interchange

When you make changes to the configuration files you need to restart the Interchange server. How this is done depends on how you installed Interchange:

Find the right command for your system and remember it, since you will need to restart Interchange a few times during the tutorial.

33.6. Tutorial assumptions

Because it is impossible to cover all scenarios, this tutorial assumes that you installed Interchange on Red Hat Linux from the RPM packages. This creates the following settings:

If you did not install with these settings, substitute the correct values for your system when these settings are mentioned in the tutorial.

34. Building Your Catalog

This section describes the pages and directories that need to be established to create a properly functioning catalog.

34.1. Create the link program

You need to make a copy of the demo link program in your cgi-bin directory and name it tutorial.

The demo link program has the same name as your demo catalog, usually foundation. The link program links the Interchange daemon with your web server. Make sure that it has the same owner and file permissions as the one you copied from. The set-UID bit is especially (unless you installed as a regular user). Normally you will need to be root to have write permissions in the cgi-bin directory.

Type this command as root while in your cgi-bin directory:

  cp -p foundation tutorial

If everything is working correctly, typing ls -l should describe your files roughly like this:

  -rwsr-xr-x    1 interch  interch      7708 Dec 16 22:47 foundation
  -rwsr-xr-x    1 interch  interch      7708 Dec 16 22:47 tutorial

34.2. Create the tutorial catalog directory

As root, create a subdirectory named tutorial under your catalogs directory (probably /var/lib/interchange/). This is where all of the catalog-specific files will go. It needs to be readable, writable, and executable by the Interchange user. This will be referred to as your catalog directory. Type the following while in the catalogs directory to create the tutorial subdirectory:

  mkdir tutorial
  chown interch.interch tutorial
  chmod 770 tutorial

34.3. Become the Interchange user

You should be able to do everything you need to do as the 'interch' user for the rest of this tutorial. So you can switch to that user now (su - interch). If you installed Interchange from the RPM, the user interch probably doesn't have a password. You'll have to set it with a command such as passwd interch while root.

34.4. Go to the tutorial catalog directory

Change to the catalog directory with the 'cd' command. For the rest of this tutorial, all file locations will be given relative to the tutorial catalog directory. For example, pages/ord/basket.html would actually be /var/lib/interchange/tutorial/pages/ord/basket.html or the equivalent on your system. The only exception is interchange.cfg, which is in the Interchange software directory.


Note: To improve clarity, we will append a trailing slash to directory names to clearly distinguish them from file names. (Similar to the output of the ls command with the -F option.)

34.5. Create the session directory

You need to create the session directory where Interchange saves information on each visitor's browsing session. If you do not have this directory, your catalog will not work. This directory is called session/ and goes under your catalog directory. Type mkdir session to create this directory.

35. Configuration files

Interchange configuration is controlled by a number of directives, which are specified in two files. Global configuration directives go in interchange.cfg in the Interchange software directory. Catalog-specific configuration directives go in catalog.cfg in the catalog directory.

A complete directive consists of the directive name followed by whitespace-separated parameters. Any number of spaces or tabs can be between the directive and its options, but the directive and its options must be on the same line. The directive is case-insensitive, but it is recommended that you use it consistently for readability.

You can insert blank lines or comment lines (lines where the first non-blank character is '#') throughout the configuration files to improve readability. The order the lines appear in is significant, but unimportant for the simple catalog you are creating.

For the next part, access your text editor (for example, vi, emacs, pico, joe, gedit, or nedit) to start editing some files.

35.1. interchange.cfg

The first directive we need to use is a global directive that tells Interchange where the new catalog is, called Catalog. The Catalog directive has the following format:

  Catalog   name   catalog_base_directory   link_url_path

Open interchange.cfg in the Interchange software directory. Go near the top of the file, right below the other Catalog directives, and add this line:

  Catalog  tutorial  /var/lib/interchange/tutorial  /cgi-bin/tutorial

Save the file.

35.2. catalog.cfg

For the rest of the tutorial, most of the files mentioned do not exist yet. You will create them yourself with initial text we give.

You need to create a catalog.cfg file for your tutorial store (in the tutorial catalog directory). We'll start with a very simple products database table with a few fields and a few products.

The Database directive describes a database table to the Interchange system in this format:

  Database  name  filename  format

Interchange has several database options available. We will use the simplest, which is the built-in default (specifically, some variant of DBM). The default location for filename is in a subdirectory called products under the catalog directory. Interchange recognizes a number of file formats. We will use a tab-delimited text file. Enter the following into catalog.cfg:

  Database  products  products.txt  TAB

This tells Interchange that you have a database table named 'products' that is described in a tab-delimited file named products.txt. You can describe an unlimited number of arbitrary database tables for the system to use this way. Interchange keeps a list of default tables called "Product Files," reflecting its e-commerce roots. You can specify all of the database tables that contain products by using the ProductFiles directive. There is no default for this, so you will have to specify your products table's name by adding the following line to catalog.cfg:

  ProductFiles  products

There are a few other directives that Interchange expects to see in order to complete the minimum configuration. They are VendURL, SecureURL, and MailOrderTo. They are, respectively, your catalog's base URL, its secure URL, and the e-mail address to mail order notices to. Add the following lines to catalog.cfg to establish these directives:

  VendURL  http://localhost/cgi-bin/tutorial
  SecureURL  http://localhost/cgi-bin/tutorial
  MailOrderTo  your@email.address

The catalog.cfg file should look like this when you save it:

  Database  products  products.txt  TAB
  ProductFiles  products
  VendURL  http://localhost/cgi-bin/tutorial
  SecureURL  http://localhost/cgi-bin/tutorial
  MailOrderTo  your@email.address

36. The products database table

36.1. products/products.txt

Create the products/ directory in your tutorial catalog directory.

The products/products.txt file will serve two purposes. It will provide Interchange with the layout of the products database table and it will also provide the data. When Interchange parses the products.txt file, it will expect the first line to contain the names of the fields for the database table (for example, sku, description, price). The first field in the list is expected to be a primary key (unique identifier) for that row. In most cases you are going to use the SKU (stock keeping unit) as the unique identifier for each product.

The product database is handled as a special case since Interchange expects at least the description, price, and product ID (sku) fields. In other words, the products.txt file must at least contain fields named sku, price, and description. You can have other fields too, if you wish.

The simple store that we are going to build will sell tests. You can choose another sample product line, but it is recommended that you keep it simple. Create the file products/products.txt to look like this, with a single tab separating each field:

  sku   description     price
  4595  Nice Bio Test   275.45
  2623  Stack of Econ Quizzes   1.24
  0198  Really Hard Physics Test        1589.34
  1299  Ubiquitous diff eq final        37.00


Note: When using tab-delimited files as we are, make sure you have exactly one tab between each field. Some text editors will use spaces to simulate tabs. Interchange expects actual ASCII tab characters; extra spaces or other characters will corrupt your data.

You may notice that the columns don't line up in your text editor. This is the nature of tab-delimited files. Do not try to fix these.

37. Page templates

Since most sites have certain aspects of the site that remain the same as the content of the pages changes, we are going to create a template that we can use for all pages. We'll divide the page into four sections:

   _____________________
  |                     |
  |         top         |
  |                     |
  |---------------------|
  |      |              |
  |      |              |
  | left |     main     |
  |      |              |
  |      |              |
  |---------------------|
  |                     |
  |        bottom       |
  |_____________________|

The "main" section holds the content that is different for each page. The "top" section is for headers, banners, menus, and so on. The "left" section can be used as a sidebar or navigation bar, and the "bottom" section can contain the copyright and contact info. The top, left, and bottom sections will remain constant throughout the site. Making a change to information in one of these sections will make that change to all pages in your site.

Now type the HTML for each template section in an individual plain text file in the catalog directory, named 'top', 'left', and 'bottom', respectively using the code displayed below. No '.html' suffixes are used on these because they are not meant to be parsed directly by Interchange as full pages.

37.1. top

  <html>
  <head>
  <title>The Interchange Test Catalog</title>
  </head>
  <body>
  <div align=center>
  <table width="80%" border cellpadding=15>
  <tr><td colspan=2 align=center><h1>The Interchange Test Catalog</h1></td></tr>

37.2. left

  <tr>
  <td align=center>(left)</td>
  <td align=center>

37.3. bottom

  </td>
  </tr>
  <tr><td colspan=2 align=center>(bottom)</td></tr>
  </table>
  </div>
  </body>
  </html>

37.4. The Interchange Tag Language

Now we need a way to pull the template pieces we just created into the proper places to make a complete page. This is done using ITL, the Interchange Tag Language.

ITL is at the heart of almost all Interchange catalog pages. It's how you use Interchange's functionality. The ITL tags appear between square brackets like [this]. Options appear after the tag, separated by whitespace, like this: [tag option1 option2] and this: [tag option1=value1 option2=value2]. They can span multiple lines. (That can help readability when the tag has many options.) There are many ITL tags, and for this tutorial very few will be addressed. For a complete listing of the ITL tags, see the Interchange Tag Reference Guide.

Your first tag will be [include], which reads the file mentioned (relative to the catalog directory), parses any Interchange tags, and puts the result in place of the tag. This is demonstrated on the next page you need to create.

38. Creating a welcome page

38.1. pages/index.html

Create a directory called pages/ in your tutorial catalog directory.

Type the following text and save it as pages/index.html. This will create a page to test that everything works so far.

  [include top]
  [include left]
  This is where your content goes.
  [include bottom]

Restart Interchange so your changes take effect. Go to your web browser and load the page. The URL should be similar to the following: http://localhost/cgi-bin/tutorial/index.html.


Note: Interchange pages in the pages/ or other directories must have the .html suffix on them. You can drop the suffix in your URL and in other places, such as the [page] tag you'll learn about later, but the file name on disk must have the suffix.

39. Troubleshooting

Your first Interchange page should have displayed as described in your browser. If it didn't, you need to figure out what went wrong. Most of the time, overlooked details are the problem. Double-checking your typing is a good habit to get into.

The following is a troubleshooting checklist to use when you run into problems:

  1. Have you created directories with the proper names in the proper locations? (See Appendix A for a full directory and file structure of the tutorial catalog.)
  2. Have you misspelled any file names or put them in the wrong directories? Are the files and parent directories readable by the interch user? Double-check with the ls command.
  3. Did you type letters in the proper case? Remember that both Unix and Interchange are case-sensitive, and for the most part you may not switch upper- and lower-case letters.
  4. Did you type all punctuation, ITL tags, and HTML tags correctly?
  5. Did you use whitespace correctly in the cases where it mattered? Remember to use tabs when tabs are called for (in lists and database text files).
  6. Did you restart Interchange if you changed anything in interchange.cfg or catalog.cfg, or if you're in a high-traffic mode?
  7. Check your catalog error log, error.log in your tutorial catalog directory, to see if Interchange reported any errors.
  8. Check the Interchange server error log, error.log in the Interchange software directory, to see if it had problems loading the catalog at all.
  9. View the HTML source of any catalog pages that are loading incorrectly to check for a coding error. The problem may reveal itself when you see what HTML the browser is getting.

40. Displaying products

40.1. Listing all products

Now that your store is running, you need to display your products on the welcome page. We will loop over all of the products in our database and produce an entry for each one in a table. Replace the line "This is where your content goes" in pages/index.html with the following:

  <table cellpadding=5>
  <tr>
  <th>Test #</th>
  <th>Description</th>
  <th>Price</th>
  </tr>

  . . .

  </table>

Now we will use Interchange tags to fill in the rest of the table from the products database you created. The [loop] [/loop] ITL tag pair tells Interchange to iterate over each item in the parameter list. In this case, the loop is over the result of an Interchange search. The search parameter does a database search on the provided parameters. In this case, we're doing a very simple search that returns all of the fields for all of the entries in the products database. The parameters passed to the search tell Interchange to return all ('ra') on the file ('fi') products respectively. The following should take the place of the ellipsis in the code you placed in index.html:

  [loop search="ra=yes/fi=products"]

  . . .

  [/loop]

In the loop we just established, the individual elements of the entry using the [loop-field] tag. The following code should replace the above ellipsis in the code we placed in pages/index.html:

  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
  </tr>

The [loop-code] tag refers to the primary key (unique identifier) for the current row of the database table in question. In this case, it will produce the same output as the [loop-field sku] tag, because the 'sku' field is the primary key for products table. In each case the tag is replaced by the appropriate element. When put together, Interchange generates a page with your products table on it.

Your finished page should look like this:

  [include top]
  [include left]
  <table cellpadding=5>
  <tr>
  <th>Test #</th>
  <th>Description</th>
  <th>Price</th>
  </tr>
  [loop search="ra=yes/fi=products"]
  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
  </tr>
  [/loop]
  </table>
  [include bottom]

Test this page by refreshing the index.html page in your browser.

40.2. pages/flypage.html

The next step is to create an individual page for each item. To do this, you need to create a special generic page called pages/flypage.html. When a page is requested that does not exist in the pages/ directory, Interchange will check and see if the requested page has the same name as a product ID from the product database table (in this case a SKU). If it does, it will show the flypage for that product. If there's no product with that ID, the special error page special_pages/missing.html (described in the next section) will be displayed.

For example, if the page 0198.html was requested, Interchange first checks for a page with that name. If one is not found, it searches the products database table for a product with that ID. Interchange then creates a product page "on the fly" using pages/flypage.html. When constructing the flypage, the entire product record for the requested product is available through the [item-field] tag (similar to the [loop-field] tag). To create a fly page, type the following code and save it as pages/flypage.html.

  [include top]
  [include left]

  <h3>Test #[item-code]</h3>
  <p>[item-field description] . . . [item-field price]</p>

  [include bottom]

Then, to provide links to the product flypages from your home page, modify pages/index.html slightly, so that:

  <td>[loop-field description]</td>

becomes:

  <td><a href="[loop-code].html">[loop-field description]</a></td>

40.3. special_pages/missing.html

Create the special_pages/ directory in your tutorial catalog directory (not in the pages/ directory).

As mentioned, it is a good idea to display an error page when Interchange is asked for an unknown page. To create a missing page for display, type the following and save it as special_pages/missing.html.

  [include top]
  [include left]
  <p>We're sorry, the page you requested has not been found.</p>

  <p>Try finding what you need on the [page index]welcome page</a>.</p>
  [include bottom]

The addition of this page ensures that users see your error message instead of a mysterious server error if they mistype a URL.

41. The shopping basket

41.1. A link for ordering

Now that you have your products available, let's add a shopping cart so customers can purchase them. This is created using the [order] tag. These tags create an HTML link that causes the specified item to be ordered and transfers the shopper to the basket page. This is a built-in shortcut to the complete order process which uses an HTML form submission process. The parameter for the [order] tag is the product ID. To add these tags to the catalog, make the following change to pages/index.html:

  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
+ <td>[order [loop-code]]Order Now</a></td>
  </tr>
  [/loop]


Note: The line you need to add is marked by a '+'. However, do not include the '+' when adding this line. The surrounding lines are shown to give you context. This style is called a "context diff" and is used often in this tutorial.

41.2. pages/ord/basket.html

Create the directory pages/ord/ in the tutorial catalog directory. In other words, ord/ should be inside the pages/ directory.

For the [order] tag, Interchange expects a default page called pages/ord/basket.html. This page displays the contents of the shopping basket and contains other shopping basket functionality.

The Foundation store has a full-featured shopping basket available for use, but this tutorial teaches you to build your own simple one. The shopping basket items can be accessed using a set of tags that have an [item] prefix. Put the following code in the new file pages/ord/basket.html. The section that follows explains the tags used.

  [include top]
  [include left]

  <h2>This is your shopping cart!</h2>

  <table cellpadding=5>

  <tr>
  <th>Qty.</th>
  <th>Description</th>
  <th>Cost</th>
  <th>Subtotal</th>
  </tr>

  [item-list]
  <tr>
  <td align=right>[item-quantity]</td>
  <td>[item-field description]</td>
  <td align=right>[item-price]</td>
  <td align=right>[item-subtotal]</td>
  </tr>
  [/item-list]

  <tr><td colspan=4></td></tr>

  <tr>
  <td colspan=3 align=right><strong>Total:</strong></td>
  <td align=right>[subtotal]</td>
  </tr>

  </table>

  <hr>

  <p>
  [page checkout]Purchase now</a><br>
  [page index]Return to shopping</a>
  </p>

  [include bottom]

The basket items can be accessed one at a time by using the [item-list] tag. So we will create a table by iterating through the basket items. The text within the [item-list] [/item-list] tags is created for each item in the list.

You also need to put a link in the index page so that shoppers can go to their shopping cart without ordering something. Modify the end of pages/index.html by adding the following lines.

  </table>
+ <hr>
+ <p align=center>[page order]View shopping cart</a></p>
  [include bottom]

Refresh the page and test the shopping basket in your browser.

42. Order checkout

42.1. pages/checkout.html

The site can now be completed by adding the ability to check out with the shopping cart and finalize the order. To do this the customer needs to provide a shipping address (which, for the sake of this tutorial, we will assume is the same as the billing address), and payment information. We will process the order by verifying the customer's payment information and sending an email to the merchant (ourselves) detailing the order.

First you need to create a checkout page. The checkout page consists of a form that receives order information from the customer and performs a simple credit card number check. In this tutorial we will use a built-in test that only checks to see if a given credit card number could be valid. If the information is acceptable the customer will move to the next phase of the order process. If it is not, an error page will be displayed.

To create a checkout page, type the following code and save it as pages/checkout.html. The section that follows explains the code.

  [include top]
  [include left]
  <h1>Checkout Page</h1>

  <form method=post action="[process]">
  <input type=hidden name=mv_todo value=submit>
  <input type=hidden name=mv_order_profile value=order_profile>
  <input type=hidden name=mv_cyber_mode value=minivend_test>

  <table cellpadding=3>

  <tr>
  <td align=right><b>First name:</b></td>
  <td><input type=text name=fname value="[value fname]"></td>
  </tr>

  <tr>
  <td align=right><b>Last name:</b></td>
  <td><input type=text name=lname value="[value lname]"></td>
  </tr>

  <tr>
  <td align=right rowspan=2><b>Address:</b></td>
  <td><input type=text name=address1 value="[value address1]"></td>
  </tr>

  <tr>
  <td><input type=text name=address2 value="[value address2]"></td>
  </tr>

  <tr>
  <td align=right><b>City:</b></td>
  <td><input type=text name=city value="[value city]"></td>
  </tr>

  <tr>
  <td align=right><b>State:</b></td>
  <td><input type=text name=state value="[value state]"></td>
  </tr>

  <tr>
  <td align=right><b>Postal code:</b></td>
  <td><input type=text name=zip value="[value zip]"></td>
  </tr>

  <tr>
  <td align=right><b>Country:</b></td>
  <td><input type=text name=country value="[value country]"></td>
  </tr>

  </table>

  <p>
  Note: We assume that your billing address is the same as your shipping address.
  </p>

  <table cellpadding=3>

  <tr>
  <td align=right><b>Credit card number:</b></td>
  <td><input type=text name=mv_credit_card_number value="" size=20></td>
  </tr>

  <tr>
  <td align=right><b>Credit card expiration date:</b></td>
  <td>
  Month (number from 1-12):
  <input type=text name=mv_credit_card_exp_month value="" size=2 maxlength=2>
  <br>
  Year (last two digits only):
  <input type=text name=mv_credit_card_exp_year value="" size=2 maxlength=2>
  </td>
  </tr>

  </table>

  <p>
  <input type=submit name=submit value="Finalize!">
  <input type=reset name=reset value="Reset">
  </p>

  </form>

  <p>[page index]Return to shopping instead</a></p>
  [include bottom]

The HTML form begins with a method of 'post' (which sends the form data as its own stream, as opposed to the 'get' method which encodes the data as part of the URL). The [process] tag creates a special URL for form processing. Interchange has a built-in form processor that is configured by submitting certain fields in the form. The Finalize button will invoke this form processor and link the user to the special_pages/receipt.html page, which is described later.

You are submitting some hidden form values that will tell Interchange how to process this form. The first value, mv_todo was set as submit. This causes the form to be submitted for validation. The second value, mv_order_profile was set as order_profile. This determines the validation process for the form. It is explained further in the next section.

The last value, mv_cyber_mode, was set to be minivend_test. The mv_cyber_mode value determines what method will be used to charge a credit card. The value of minivend_test uses the internal test method, which calculates a simple checksum against the card to determine if it is a valid number.

When preparing an order for processing, Interchange looks for certain named fields in the form values for name, address, and credit card information. We are using all expected field names in this form so that no translation needs to take place.

View the checkout page in your browser. The "Finalize!" link has not been enabled, but the page should display properly.

42.2. etc/profiles.order

Create the etc/ directory in the tutorial catalog directory now.

You need to set up verification for the order form by defining an order profile for the form. An order profile determines what fields are necessary for the form to be accepted. Create an order profile verification page by typing the following and saving it as etc/profiles.order. The section that follows explains the code used.

  __NAME__ order_profile

  fname=required
  lname=required
  address1=required
  city=required
  state=required
  zip=required

  &fatal=yes
  &final=yes

  __END__

A single file can contain multiple profile definitions. First the profile is named using the __NAME__ pragma. (This is unrelated to the __VARIABLE__ syntax seen elsewhere in Interchange.) Then in the profile there is a list of the form fields that are required. The &fatal setting indicates that validation will fail if any of the requirements are not met. &final indicates that this form will complete the ordering process. This setting is helpful if you have a multi-page ordering process and you want to validate each page individually. The __END__ pragma signals the end of this profile, after which you can begin another one.

In order to activate your order profile, add the following OrderProfile directive to the end of catalog.cfg:

  OrderProfile etc/profiles.order

Watch for white space in front of the __NAME__ pragma, it can cause your profile to be ignored. Rember to restart Interchange for any changes to take effect.

42.3. special_pages/needfield.html

If the submitted form lacks a required field, Interchange will display an error page. The default location is special_pages/needfield.html. To create this page, type the following text and save it as special_pages/needfield.html.

  [include top]
  [include left]
  <p>The following information was not given:</p>

  <p><b>[error all=1 show_var=1 show_error=1 joiner='<br>']</b></p>

  <p>Please go back to the [page checkout]checkout page</a>
  and fill out the form properly.</p>

  [include bottom]

The [error] tag is the most important tag on this page. The all parameter tells the tag to iterate through all of the errors reported from the failed verification, and the show_var parameter indicates that the failed variable name should be displayed. For example, if the first name was left empty, fname would be shown. The show_error parameter displays the actual error for the variable. The joiner parameter inserts an HTML <br> tag between each error message, so each error is displayed on its own line. In more complex configurations, the [error] tag can be even more expressive.

42.4. Credit card processing

This tutorial uses a very simple order process. To accomplish this, one more directive needs to be added to the file etc/profiles.order:

  &fatal=yes
  &final=yes
+ &credit_card=standard keep

  __END__

This issues two instructions to the credit card system.

The first option, standard, uses the standard built-in encryption algorithm to encrypt the credit card number and erases the unencrypted copy from memory. We are using the standard option not to encrypt the number but to run the checksum verification on the number to verify that it is a potentially correct number. We will not be checking with a real payment processor to see if it actually is a valid card number. For testing purposes, you can use the card number 4111 1111 1111 1111, which will pass the checksum test.

The second option, keep, keeps the credit card number from getting removed from memory. We want to keep the number in memory so that it is available when it is mailed as part of the order.

If the credit card number passes and all of the required fields are present, the customer will be sent to the final page. Interchange then sends an e-mail to the store owner (you).

42.5. etc/report

When the customer's involvement in the order is complete, Interchange composes an email and sends it to the recipient defined in the MailOrderTo directive in catalog.cfg. The default location for the template for this email report is etc/report. Interchange tags can be used to fill in the body of the message.

The report should include at least the customer's name, address, and the items they ordered. The following is a simple report template; save it as etc/report.

               Name: [value fname] [value lname]
            Address: [value address1][if value address2]
                     [value address2][/if]
  City, State, etc.: [value city], [value state]  [value zip] [value country]

      Credit Card #: [cgi mv_credit_card_number]
    Expiration Date: [cgi mv_credit_card_exp_month]/[cgi mv_credit_card_exp_year]


  ************ ORDER ************
  [item-list]
  [item-quantity] x [item-description] ([item-code]), [item-price] ea.
  [/item-list]
  Subtotal: [subtotal]
     Total: [total-cost]

This file is in plain text format where, unlike HTML, white space is relevant. It is fairly straightforward, except that the [if] tag was added to only include the optional second address line if the customer filled it in.

One of the special properties of the mv_credit_card_number field is that Interchange specifically precludes the credit card number from being saved. This makes it unavailable to you in the [value] tag. The [cgi] tag is used to circumvent this important security measure in order to get the value submitted from the last form.

WARNING! Obviously it is a bad idea to send a real credit card number over an insecure channel like email. In a real configuration, you would encrypt the number securely before emailing or storing it.

42.6. special_pages/receipt.html

Once the report has been run, Interchange will finish the order process on the customer side by displaying a success screen containing a receipt. The default location for this page is special_pages/receipt.html. To create a receipt page, type the following code and save it as special_pages/receipt.html.

  [include top]
  [include left]
  <p>Thank you for ordering stuff from us.<br>Have a nice day!</p>
  <p>[page index]Return to our welcome page</a></p>
  [include bottom]

Once the order is processed, the customer's shopping cart is emptied.

At this point you have a more-or-less functional store. Congratulations.

43. Enhancing the catalog

Now that you have a working catalog, you can go back and add improvements and test them incrementally. This section walks you through several and then suggests more enhancements you can attempt on your own.

43.1. Price pictures

You may have noticed that the product prices aren't formatted as prices usually are. The way to correct this is with an Interchange feature called price pictures.

There are several properties to price pictures: the currency symbol, the thousands separator, the decimal point, the number of digits to show behind the decimal, and so on. Most Unix systems have U.S. currency and the English language as the default locale, which is called en_US. The only thing you need to do on such a system is specify the currency symbol, which, in this case, is the dollar sign. To do this, add the following line to your catalog.cfg file:

  Locale en_US currency_symbol $

Restart Interchange and view your catalog. You will notice little has changed on the welcome page or the flypages, but in the shopping cart all your prices should be formatted as U.S. dollars ("1347.3" has become "$1,347.30"). This is because Interchange automatically formats shopping cart prices as currency. To turn off this feature, you would have to change the [item-price] tag to [item-price noformat] in pages/ord/basket.html.

But that's probably not what you want to do. You're probably more interested in formatting your other prices as currency. To do that, simply use the [currency] [/currency] tag pair for all price values. Make the following change to pages/index.html:

  [loop search="ra=yes/fi=products"]
  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
- <td align=right>[loop-field price]</td>
+ <td align=right>[currency][loop-field price][/currency]</td>
  </tr>
  [/loop]


Note: The line that begins with '-' should be deleted. Do not type the '-'. The next line, that starts with '+', replaces it.

A similar change to the [item-field price] tag in the pages/flypage.html page will fix that currency display. View the page in your browser. All your prices should be formatted for U.S. currency.

If your prices are not being formatted correctly, your default system locale may be set up differently or your en_US locale settings may be wrong. There are a few other catalog.cfg directives you can use to correct the situation:

  Locale en_US p_cs_precedes 1

Makes the currency symbol precede the currency value. A '0' setting makes the symbol come after the currency value.

  Locale en_US mon_thousands_sep ,

Sets your thousands separator to a comma. It can be set to any value.

  Locale en_US mon_decimal_point .

Sets your decimal separator to a comma. Many countries use a comma instead of a period to separate the integer from the decimal part.


Note: Consult the Interchange documentation and your operating system manual for more information on locale settings.

43.2. Catalog variables

Interchange provides a very useful feature that has not been discussed yet called catalog variables. It provides a way for you to set a variable to a certain value in the catalog.cfg file and use it anywhere in your catalog pages. The Variable directive allows an Interchange catalog variable to be created with the name coming from the first parameter and the value from the rest of the line, like this:

  Variable SOMENAME whatever value you want

To access that variable in your pages, type the token __SOMENAME__. Notice that there are two underscore characters before the variable name and two after it, and that in place of the word SOMENAME you would put the actual name of the variable. The first thing Interchange does on a page is to replace the token with the variable's value. The value can also include Interchange tags to be parsed.

43.3. A more interesting page footer

You can put a contact email address at the bottom of each page in case your customers want to contact you. You could just add it to the footer, but by putting it into a variable you can use it in contact pages as well. This allows you to easily change the variable information and have that change reflected in all instances of that variable. The following is an example of how to set a catalog variable in catalog.cfg:

  Variable CONTACT_EMAIL someone@your.domain

Now make the following change to your template file bottom:

  </td>
  </tr>
- <tr><td colspan=2>(bottom)</td></tr>
+ <tr><td colspan=2><a href="mailto:__CONTACT_EMAIL__">Contact us</a>
+ if you have any questions.</td></tr>
  </table>
  </div>
  </body>
  </html>

Be sure to restart Interchange before reloading the page in your browser, since you made a change to catalog.cfg.

Let's add another variable to your catalog. This variable demonstrates how an Interchange tag can be included in the variable. This Interchange tag returns the current date in a standard format. Add the following to catalog.cfg:

  Variable DISPLAYDATE [time]%A, %B %d, %Y[/time]


Note: See the Interchange Tag Reference Guide for an explanation of the [time] tag.

Now add the following to the left template piece:

  <tr>
- <td align=center>(left)</td>
+ <td align=center>__DISPLAYDATE__</td>
  <td align=center>

Restart Interchange and view the page.

43.4. Advanced credit card expiration date selection

To reduce the possibility of human error at checkout time, most online stores use a pull-down option menu to list the months and the years for the credit card expiration date, instead of having the user to type the numbers by hand. It also lets you avoid explaining whether the user should enter a 2- or 4-digit year.

Make the following change to your pages/checkout.html page. The section that follows explains the code. Read the explanation section below before typing the code to be sure you know where tabs should be used instead of spaces and where to watch out for `backticks`.

  <tr>
  <td align=right><b>Credit card expiration date:</b></td>
  <td>
- Month (number from 1-12):
- <input type=text name=mv_credit_card_exp_month value="" size=2 maxlength=2>
- <br>
- Year (last two digits only):
- <input type=text name=mv_credit_card_exp_year value="" size=2 maxlength=2>
+
+ Month:
+ <select name=mv_credit_card_exp_month>
+ [loop
+    lr=1
+    option=mv_credit_card_exp_month
+    list="
+ 1     01 - January
+ 2     02 - February
+ 3     03 - March
+ 4     04 - April
+ 5     05 - May
+ 6     06 - June
+ 7     07 - July
+ 8     08 - August
+ 9     09 - September
+ 10    10 - October
+ 11    11 - November
+ 12    12 - December"]
+ <option value="[loop-code]">[loop-pos 1]
+ [/loop]
+ </select>
+
+ Year:
+ <select name=mv_credit_card_exp_year>
+ [comment]
+    This should always return the current year as the first, then
+    seven more years.
+ [/comment]
+ [loop option=mv_credit_card_exp_year lr=1 list=`
+   my $year = $Tag->time( '', { format => '%Y' }, '%Y' );
+   my $out = '';
+   for ($year .. $year + 7) {
+     /\d\d(\d\d)/;
+     $last_two = $1;
+     $out .= "$last_two\t$_\n";
+   }
+   return $out;
+ `]
+   <option value="[loop-code]">[loop-pos 1]
+ [/loop]
+ </select>
+
  </td>
  </tr>

  </table>

In the first set of <select> </select> tags a list is generated of the months to choose from. This is accomplished by using a [loop] tag. In this case we are looping over an explicit list. The list is provided in the list parameter. Use caution when typing this, as it is sensitive to formatting (which may not be reflected in this document). Make sure that the numbers are the first characters on each new line and that the elements are separated by a single tab. Since the columns in this list are not named, the first element can be accessed using [loop-code] or [loop-pos 0] with subsequent elements being accessed by [loop-pos N] where N is the number of the element you want. Notice that the elements are zero-indexed. Each time through this loop Interchange generates a select <option> with a number as the value and the name of the month as the text for the select menu.

For the next set of <select> </select> tags embedded Perl is used to generate the list which is iterated over. Perl code can be embedded in Interchange pages in order to extend the abilities of the system. Make sure you typed backticks (grave accents) after "list=" and before the closing bracket and not apostrophes. This code generates an entry for seven years in addition to the current year. It is not necessary at this point for you to understand this Perl code.

43.5. Sorting the product list

The products listed on your welcome page are shown in the same order that you entered them into products/products.txt. As you add more products, you will want this list to show up in a predictable order. To do this, you need to change the search parameters in index.html, which were originally:

  [loop search="
          ra=yes
          fi=products
          "]

You will recall that 'ra' stands for 'return all' and 'fi' stands for file. Let's add the search parameter 'tf', which specifies the sort field. You can specify the field either by name or by number (starting with 0), with names and order as given in the first line of products/products.txt). Make the following change in index.html:

  [loop search="
          ra=yes
          fi=products
          tf=price
          "]

Refresh your browser. The default ordering is done on a character-by-character basis, but we were looking to do a numeric sort. For this you need to set 'to', the sort order, to 'n', for numeric:

  [loop search="
          ra=yes
          fi=products
          tf=price
          to=n
          "]

Refresh your browser. Now try reversing the sort order by adding 'r' to the 'to' setting:

  [loop search="
          ra=yes
          fi=products
          tf=2
          to=nr
          "]

You'll notice that it worked equally well to specify the sort field by number instead of name. You could also do a reverse alphabetical sort by description:

  [loop search="
          ra=yes
          fi=products
          tf=1
          to=r
          "]

Now let's try narrowing the search down a bit. Instead of returning all, we'll give 'se', the search parameter, and and use 'su', which allows substring matches. To search only for products that have the word "test" in one of their fields, and sort the results by description, type:

  [loop search="
          se=test
          su=yes
          fi=products
          tf=description
          "]

Which seems like something that would be better done in a search box for your store visitors.

Before moving on, change this search back to the simple list, sorted by description:

  [loop search="ra=yes/fi=products/tf=description"]

43.6. Adding a search box

Your customers might appreciate the ability to search for a test by SKU or part of the test description. To do this, you need to add a search box to the left portion of the page layout. Make the following change to the file left:

  <tr>
- <td align=center>__DISPLAYDATE__</td>
+ <td align=center>
+ <form action="[area search]" method=post>
+ Search:<br>
+ [set testname]
+    su=yes
+    fi=product
+    sf=sk
+    sf=descriptio
+  [/set]
+ <input type=hidden name=mv_profile value=testname>
+ <input type=text name=mv_searchspec size=15 value="">
+ </form>
+ <hr>
+ __DISPLAYDATE__
+ </td>
  <td align=center>

This is a simple HTML form with a single input box for text. The action goes to a special Interchange processor called 'search' that will perform the search and pass the results to a page called pages/results.html (that has not been created yet).

The [set testname] ... [/set] tags set an Interchange 'value' variable that, in this case, will be used as a predefined search profile. We specify all the search parameters except the one the user will enter, 'mv_searchspec' (the long name for 'se'). We then tell Interchange we want to use this search profile in a hidden form tag named 'mv_profile'.

The search box will now appear on all catalog pages, but you still need to create the search results page. To create the search results page, type the following code and save it as pages/results.html.

  [include top]
  [include left]
  <h3>Search Results</h3>
  [search-region]
    [on-match]
      <table cellpadding=5>
      <tr>
      <th>Test #</th>
      <th>Description</th>
      <th>Price</th>
      </tr>
    [/on-match]
    [search-list]
      <tr>
      <td>[item-code]</td>
      <td><a href="[item-code].html">[item-field description]</a></td>
      <td align=right>[item-field price]</td>
      <td>[order [item-code]]order now</a></td>
      </tr>
    [/search-list]
    [on-match]
      </table>
    [/on-match]
    [no-match]
      <p>Sorry, no matches were found for '[cgi mv_searchspec]'.</p>
    [/no-match]
  [/search-region]
  <hr>
  <p align=center>[page index]Return to welcome page</a></p>
  <p align=center>[page order]View shopping cart</a></p>
  [include bottom]

The search results will be contained in the [search-region] [/search-region] tags. The text in the [on-match] [/on-match] container will be displayed only if matches were found for the search. The text in the [no-match] [/no-match] container will be displayed only if no matches were found. The [search-list] [/search-list] container functions just like [loop] [/loop], iterating over its contents for each item in the search results list.

43.7. The default catalog page

As you know, a standard Interchange catalog page URL looks like this:

  http://localhost/cgi-bin/tutorial/index.html

But what happens if you leave off the page name, as people often do when typing URLs in by hand? Type:

  http://localhost/cgi-bin/tutorial

and you get a server error message. We can change this by adding the following directive to catalog.cfg:

  SpecialPage catalog index

Restart Interchange and try the above URL again.


Note: If you want to make the welcome page something other than pages/index.html, modify the 'index' part of the directive appropriately.

43.8. High-traffic changes

Through this tutorial you have created catalog pages that use the [include] tag to include template pieces in the pages. This has worked well, but there are a few drawbacks. First, if you want to rename any of the template piece files or move them out of the main catalog directory and into their own subdirectory, you would have to update the [include] tag on every page. To avoid this, you can create catalog variables set to the [include] tags. Add these lines to your catalog.cfg file:

  Variable TOP    [include top]
  Variable LEFT   [include left]
  Variable BOTTOM [include bottom]

Now change every instance of [include top] to __TOP__, doing the same for each [include] tag. At this point, you might not want to do a search-and-replace on all the .html files you just created, but keep this capability in mind for the next catalog you work on.

If you made all of the replacements and then renamed and moved your top file, you would only have to make a single change for each region in catalog.cfg to get your pages up to date:

  Variable TOP    [include templates/main-top]

And so on, depending on your naming scheme.

43.9. High traffic mode

Every time a catalog page is viewed, each file in an [include] tag must be loaded from disk. In a test situation, this takes no noticeable amount of time. But on a busy Interchange server, this can slow your system.

You can switch to a high-traffic mode that doesn't require each template piece to be read from disk every time the page is loaded. Instead, all of the pieces are read into variables once when Interchange is started and they remain in memory until Interchange is restarted. On very busy Interchange catalogs, this can increase your speed noticeably. The only drawback is that you need to restart the Interchange daemon when you make changes to the template pieces in order to have the changes take effect. You can set up high-traffic templates by changing the Variable directives in catalog.cfg as follows:

  Variable TOP    <top
  Variable LEFT   <left
  Variable BOTTOM <bottom

44. Ideas for further enhancements

You can expand your skill with Interchange by adding more functionality to your test catalog. Here are some simple ideas to get you started:

G. Catalog directory structure

This diagram shows the directory and file structure used for the 'tutorial' catalog you built. The base will be a directory with the name of your catalog:

  tutorial/
  |
  |----bottom
  |----catalog.cfg
  |----error.log *
  |----etc/
       |----profiles.order
       |----report
  |----left
  |----pages/
       |----checkout.html
       |----flypage.html
       |----index.html
       |----ord/
            |----basket.html
       |----results.html
  |----products/
       |----products.gdbm *
       |----products.txt
  |----session/
       |----(many subdirectories and files) *
  |----special_pages/
       |----missing.html
       |----needfield.html
       |----receipt.html
  |----tmp/ *
  |----top

* denotes files that are automatically created by Interchange at run time. The name of products.gdbm may vary on your system depending on your Perl setup and default system DBM libraries.

H. Document history

October 2000. Conceived and written by Sonny Cook.

December 2000. Edited and expanded by Jon Jensen.

January 2001. Proofread and clarified by Alison Smith and David Adams.

12 January 2001. First public release.

12 April 2002. Remove mention of obsolete Red Hat Linux 6-specific RPMs.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Configuration Reference

45. Interchange Configuration Files

This is an alphabetical reference to the configuration directives used in Interchange global and catalog configuration files.

Interchange has multiple catalog capability, and therefore splits its configuration into two pieces. One is global, interchange.cfg, and affects every catalog running under it. The other, catalog.cfg is specific to an individual catalog, and has no effect on other catalogs.

45.1. Directive syntax

Configuration directives are normally specified with the directive as the first word on the line, with its value or values following. Capitalization of the directive name is not significant. Leading and trailing whitespace is stripped from the line.

Including files in directives

Additional files may be called with an include file notation like this:

DirectiveName <includefile

Files included from interchange.cfg are relative to the Interchange software directory. Files included from catalog.cfg are relative to the catalog directory.

Here documents

A "here document" can be used to spread directive values over several lines, with the usual Perl <<MARKER syntax. No semicolon is used 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

That is equivalent to:

        DirectiveName setting1 setting2 setting3

Include single setting from file

        Variable MYSTUFF <file

include

        include common.cfg
        include usertag/*

ifdef and ifndef

        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@localhost
        endif

46. interchange.cfg

The VendRoot directory, specified in the main program interchange, is the default location of all of the Interchange program, configuration, special, and library files. Unless changed in the call to interchange, the main Interchange server configuration file will be interchange.cfg in the VendRoot directory.

The directives defined in interchange.cfg affect the entire Interchange server and all catalogs running under it. Multiple Interchange servers may be run on the same machine with totally independent operation.

Following is an alphabetical listing of all global configuration directives.

46.1. AcceptRedirect *global*

Enables processing of HTTP server redirects, i.e. when handling ErrorDocument for Apache. For instance, if you have in Apache httpd.conf:

        ## Setting in httpd.conf
        ErrorDocument 404 /cgi-bin/foundation

At that point, a request for /somedir/index.html that is not found will be equivalent to /cgi-bin/foundation/somedir/index.html and will be indistinguishable from the Apache-served page by the client.

        AcceptRedirect  Yes

A Yes/No directive, default No.

Caution should be taken not to enable the ErrorDocument to redirect to Interchange globally -- it would render you subject to a denial-of-service attack at random URLs, i.e. a flood of MS Windows "Code Red" attacks. It is recommended that you enable it only for specific directories, as Apache or another HTTP server will stand up much better under such a flood.

46.2. ActionMap *global*

Allows setting of Interchange form actions, usually with a Perl subroutine. Actions are page names like:

process  Perform a processing function
order    Order items
scan     Search based on path info
search   Search based on submitted form variables

The global version of ActionMap applies to all catalogs. If the same action is specified in catalog.cfg, it will pertain. See ActionMap in that section.

46.3. AddDirective *global*

Adds a configuration directive that will be parsed for every catalog.cfg file. Accepts three parameters: the name of the directive, the name of the parser (if any), and the default value (if any). The following definition would add a directive "Foo," with parser "parse_bar," and a default value of "Hello, world!":

   AddDirective  Foo  bar "Hello, world!"

If the parser is not defined, the directive value will be scalar and the same as what the user passes in the config file. If defined, the parser must be extant before it can be referenced, is always resident in Vend::Config, and begins with the string parse_.

46.4. AllowGlobal *global*

Specifies catalog identifiers that may define subroutines and UserTag entries that can operate with the full permissions of the server. Don't use this unless the catalog user is trusted implicitly. Default is blank.

   AllowGlobal  simple

Using AllowGlobal is never necessary, and is always dangerous in a multi-user environment. Its use is not recommended.

46.5. AutoVariable *global*

Specifies directives which should be translated to Variable settings. For scalars, the directive name becomes the Variable name and yields its value, i.e. ErrorFile becomes __ErrorFile__, which would by default be error.log. Array variables have a _N added, where _N is the ordinal index, i.e. SafeUntrap becomes __SafeUntrap_0__, __SafeUntrap_1__, etc. Hash variables have a _KEY added, i.e. SysLog becomes __SysLog_command__, __SysLog_facility__, etc. Doesn't handle hash keys that have non-word characters or whitespace. Only single-level arrays and hashes are translated properly.

See AutoVariable in catalog.cfg.

46.6. Capability *global*

Just like Require or Suggest, but can never cause a warning or message. This allows a module to be loaded if available and for a program to check for that capability later and adapt itself to the configuration.

   Capability  module  Archive::Zip

46.7. Catalog *global*

Specifies a catalog that can run using this Interchange server. This directive is usually inserted into interchange.cfg by the makecat program when you build a new catalog.

There are three required parameters, as shown in this example:

   Catalog  simple /home/interchange/simple /cgi-bin/simple

The first is the name of the catalog. It will be referred to by that name in error, warning, and informational messages. It must contain only alphanumeric characters, hyphens, and underscores. It is highly recommended that it be all lower case.

The second is the base directory of the catalog. If the directory does not contain a catalog.cfg file, the server will report an error and refuse to start.

The third is the SCRIPT_NAME of the link program that runs the catalog. This is how the catalog is selected for operation. Any number of alias script names may be specified as additional parameters. This allows the calling path to be different while still calling the same catalog:

   Catalog  simple /home/interchange/simple /cgi-bin/simple /simple

This is useful when calling an SSL server or a members-only alias that requires a username/password via HTTP Basic authorization. All branched links will be called using the aliased URL.

The script names must be unique among CGI program paths that run on this server; the same name cannot be used for more than one catalog unless the FullURL directive is specified. In this case, the parameter may be specified as:

        www.yourcompany.com/cgi-bin/simple
        www.theirs.com/cgi-bin/simple

Each of those 'simple' catalogs would then call a different catalog.

Optionally, individual Catalog directives that specify each of the different parameters may be used. The equivalent of our original example directive above is:

   Catalog simple directory /home/interchange/simple
   Catalog simple script    /cgi-bin/simple
   Catalog simple alias     /simple

Global directives may be specified that will change for that catalog only. This is mostly useful for ErrorFile and DisplayErrors:

   Catalog simple directive ErrorFile /var/log/interchange/simple_error.log

46.8. CheckHTML *global*

Set to the name of an external program that will check the user's HTML when they set [flag checkhtml] or [tag flag checkhtml][/tag] in their page.

   CheckHTML  /usr/local/bin/weblint

46.9. CodeDef *global*

A generic subroutine mapper that allows mapping of a subroutine as a ActionMap, CoreTag, Filter, FormAction, GlobalSub, ItemAction, LocaleChange, OrderCheck, UserTag, Widget.

46.10. ConfigAllAfter *global*

The name of a file (or files) which should be read as a part of every catalog's configuration, after any other configuration files are read. Default is catalog_after.cfg.

   ConfigAllAfter   check_actions.cfg check_variables.cfg

46.11. ConfigAllBefore *global*

The name of a file (or files) which should be read as a part of every catalog's configuration, before any other configuration files are read. Default is catalog_before.cfg.

   ConfigAllBefore   set_actions.cfg set_variables.cfg

46.12. ConfigParseComments *global*

Set to No if you want old-style '#include', '#ifdef', or '#ifndef' to be treated as the comments they appear to be. The default is Yes, which means both '#include' and 'include' do the same thing. (Use a space after the '#' if you really want to comment out the command.)

Interchange prior to version 4.7 used a different syntax for meta-directives 'include', 'ifdef', and 'ifndef' in configuration files. The commands were borrowed from the C preprocessor, and true to their C heritage, they started with '#': '#include', '#ifdef', '#ifndef'. Interchange configuration files, unlike C, uses '#' to begin one-line comments, which meant that a newcomer at first glance might assume that:

#Variable DEBUG 1
#include more.cfg

were both comments, when in fact the second was a live #include command.

To begin to make things more consistent, Interchange 4.7 and up now recognize those meta-directives without the leading '#', and the included demo catalog sets this directive to No so that lines beginning with '#' really are skipped as comments, regardless of what comes after.

46.13. Database *global*

Defines a database which is global and available to all catalogs. Writing can be controlled by catalog. See Database.

46.14. DataTrace *global*

Set DBI to trace at the level specified. Valid values are:

0 - Trace disabled.

1 - Trace DBI method calls returning with results or errors.

2 - Trace method entry with parameters and returning with results.

3 - As above, adding some high-level information from the driver and some internal information from the DBI.

4 - As above, adding more detailed information from the driver. Also includes DBI mutex information when using threaded Perl.

5 and above - As above but with more and more obscure information.

Trace level 1 is best for most Interchange debug situations. Trace will only be enabled when DebugFile is specified, as that file is the target for the trace. Example:

    DataTrace   1

Default is 0. Directive added in 4.7.0.

46.15. DebugFile *global*

Names a file, relative to the Interchange root directory, which should store the output of logDebug statements, and warnings if warnings are enabled.

        DebugFile  /tmp/icdebug

46.16. DeleteDirective *global*

Deletes a configuration directive from the list is parsed for every catalog.cfg file. Can save memory for installations with large numbers of catalogs.

   DeleteDirective  DescriptionField OfflineDir

The directive is not case-sensitive. Has no effect on global directives.

46.17. DisplayErrors *global*

While all errors are reported in the error log file, errors can also be displayed by the browser. This is convenient while testing a configuration. Unless this is set, the DisplayErrors setting in the user catalogs will have no effect. Default is No.

   DisplayErrors       Yes


Note: This changes the value of $SIG{__DIE__} and may have other effects on program operation. This should NEVER be used for normal operation.

46.18. DomainTail *global*

Implements the domain/IP session qualifiers so that only the major domain is used to qualify the session ID. This is a compromise on security, but it allows non-cookie-accepting browsers to use multiple proxy servers in the same domain. Default is Yes.

   DomainTail No

If encrypting credit cards with PGP or GPG, or are using a payment service like CyberCash, look at the WideOpen directive, which enables more browser compatibility at the cost of some security.

46.19. DumpStructure *global*

Tells Interchange to dump the structure of catalogs and the Interchange server to a file with the catalog name and the extension .structure. Use this to see how directives have been set.

46.20. EncryptProgram *global*

Specifies the default encryption program that should be used to encrypt credit card numbers and other sensitive information. Default is gpg if found on the system; then pgpe, if found; then pgp, and finally none, disabling encryption.

This is used to set the default in catalog.cfg, which has its own independent setting of EncryptProgram.

46.21. Environment *global*

Environment variables to inherit from the calling CGI link program. An example might be PGPPATH, used to set the directory which PGP will use to find its key ring.

   Environment  MOD_PERL REMOTE_USER PGPPATH

46.22. ErrorFile *global*

Sets the name of the global error log. The default is error.log in the Interchange software directory.

   ErrorFile  /var/log/interchange/log

Of course, the user ID running the Interchange server must have permission to write that file.

Optionally, syslog error logging can be set up as well. See SysLog.

46.23. FormAction *global*

Allows a form action (like the standard ones return, submit, refresh, etc.) to be set up. It requires a Perl subroutine as a target:

   FormAction foo <<EOR
   sub {
       $CGI->{mv_nextpage} = 'bar';
   }
   EOR

If it returns a true (non-zero, non-empty) value, Interchange will display the page defined in $CGI->{mv_nextpage}. Otherwise, Interchange will not display any page. The default Interchange actions can be overridden, if desired. There is also a catalog-specific version of this directive, which overrides any action of the same name.

The global version affects all catalogs -- there is also a catalog-specific version of FormAction which is protected by Safe.

46.24. FullUrl *global*

Normally Interchange determines which catalog to call by determining the SCRIPT_NAME from the CGI call. This means that different (and maybe virtual) hosts cannot use the same SCRIPT_NAME to call different catalogs. Set FullUrl to Yes to differentiate based on the calling host. Then, set the server name in the Catalog directive accordingly, such as yourdomain.com/cgi-bin/simple. A yes/no directive, the default is No.

   FullUrl  Yes

If it is set in this fashion, all catalogs must be defined in this fashion. NOTE: The individual catalog setting will not work, as this is used before the catalog name is known.

46.25. GlobalSub *global*

Defines a global subroutine for use by the [perl sub] subname arg /perl] construct. Use the "here document" capability of Interchange configuration files to make it easy to define:

   GlobalSub <<EOF

   sub count_orders {
       my $counter = new File::CounterFile "/tmp/count_orders", '1';
       my $number = $counter->inc();
       return "There have been $number orders placed.\n";
   }
   EOF

As with Perl "here documents," the EOF (or other end marker) must be the ONLY thing on the line, with no leading or trailing white space. Do not append a semicolon to the marker. (The above marker appears indented. It should not be that way in the file!)

IMPORTANT NOTE: These global subroutines are not subject to security checks. They can do most anything! For most purposes, scratch subroutines or catalog subroutines (also Sub) are better.

GlobalSub routines are subject to full Perl use strict checking, so errors are possible if lexical variables or complete package qualifications are not used for the variables.

46.26. HammerLock *global*

The number of seconds after which a locked session could be considered to be lost due to malfunction. This will kill the lock on the session. Only here for monitoring of session hand-off. If this error shows up in the error log, the system setup should be examined. Default is 30.

   HammerLock          60

This mostly doesn't apply to Interchange when using the default file-based sessions.

46.27. HitCount *global*

Increments a counter in ConfDir for every access to the catalog. The file is named hits.catalogname, where catalogname is the short catalog identifier. A Yes/No directive, default is No.

   HitCount  Yes

46.28. HouseKeeping *global*

How often, in seconds, the Interchange server will "wake up" and look for user reconfiguration requests and hung search processes. On some systems, this wakeup is the only time the server will terminate in response to a stop command. Default is 60.

   HouseKeeping    5

46.29. Inet_Mode *global*

Determines whether INET-domain sockets will be monitored on startup. Overridden by the command-line parameter -i. Default is Yes.

46.30. IpHead *global*

Implements the domain/IP session qualifiers so that only the first IpQuad dot-quads of the IP address are used to qualify the session ID. The default is 1. This is a slight compromise on security, but it allows non-cookie-accepting browsers, like AOL's V2.0, to use multiple proxy servers.

DomainTail is preferable unless one of your HTTP servers does not do host name lookups. Default is No, and DomainTail must be set to No for it to operate.

   IpHead Yes

46.31. IpQuad *global*

The number of dot-quads that IpHead will look at. Default is 1.

   IpQuad  2

46.32. Locale *global*

Sets the global Locale for use in error messages. Normally set from a file's contents, as in the example before:

   Locale <locale.error

46.33. LockoutCommand *global*

The name of a command (as it would be entered from the shell) that will lock out the host IP of an offending system. The IP address will be substituted for the first occurrence of the string %s. This will be executed with the user ID that Interchange runs under, so any commands that require root access will have to be wrapped with an SUID program.

On Linux, a host may be locked out with:

   ipfwadm -I -i deny -S %s

This would require root permissions, however, under normal circumstances. Use sudo or another method to wrap and allow the command.

A script can be written which modifies an appropriate access control file, such as .htaccess for your CGI directory, to do another level of lockout. A simple command line containing perl -0777 -npi -e 's/deny/deny from %s\ndeny/' /home/me/cgi-bin/.htaccess would work as well (remember, the %s will become the IP address of the offending user).

   LockoutCommand   lockout %s

46.34. LockType *global*

Allows selection of file locking method used throughout Interchange. Options are 'flock', 'fcntl', and 'none'. Added in 4.7.0. Please note that due to a bug this directive only works in Interchange 4.8.6 and above.

Default is flock. See the flock(2) manpage for details.

The fcntl setting is needed for NFS filesystems; for NFS-based locking to work, the NFS lock daemon (lockd) must be enabled and running on both the NFS client and server. Locking with fcntl works on Linux and should work on Solaris, but is not guaranteed to work on all OSes.

The none setting turns off file locking entirely, but that is never recommended. It might be useful to check if locking is causing hangs on the system.

If you are only accessing sessions on an NFS-mounted directory but the rest of Interchange is on the local filesystem, you can instead set the SessionType catalog directive to 'NFS', which enables fcntl locking for sessions only on a per-catalog basis.

46.35. Mall *global*

Set to Yes to issue cookies only for the current catalog's script. By default, when Interchange issues a cookie it does so for the base domain. This will allow multiple catalogs to operate on the same domain without interfering with each others session ID.

A yes/no directive.

   Mall   Yes

46.36. MaxRequestsPerChild *global*

The maximum number of requests a page server will handle before it commits suicide and asks for a replacement server. This prevents runaway memory leaks.

        MaxRequestsPerChild  100

Default is 50. Only applies in PreFork mode.

46.37. MaxServers *global*

The maximum number of servers that will be spawned to handle page requests. If more than MaxServers requests are pending, they will be queued (within the defined capability of the operating system, usually five pending requests) until the number of active servers goes below that value.

   MaxServers     4

Default is 10.

46.38. NoAbsolute *global*

Whether Interchange [file ...] and other tags can read any file on the system (that is readable by the user id running the Interchange daemon). The default is No, which allows any file to be read. This should be changed in a multi-user environment to minimize security problems.

   NoAbsolute     Yes

Note that this does not apply to tests for whether a file exists, as with [if file ...]. Such operations are allowed regardless of the NoAbsolute setting.

46.39. PIDcheck *global*

If non-zero, enables a check of running Interchange processes during the housekeeping routine. If a process has been running (or is hung) for longer than PIDcheck seconds then a kill -9 will be issued and the server count decremented. During the housekeeping routine, the number of servers checked by MaxServers will be recounted based on PID files.

Default is 0, disabling the check.

   PIDcheck   300

If you have long-running database builds, this needs to be disabled. Set it to a high value (perhaps 600, for 10 minutes), or use the offline script.

46.40. PIDfile *global*

The file which will contain the Interchange server process ID so that it can be read to determine which process should be sent a signal for stopping or reconfiguring the server.

   PIDfile  /var/run/interchange/interchange.pid

This file must be writable by the Interchange server user ID.

46.41. PreFork *global*

Causes Interchange to run in pre-forking server mode, where a number of Interchange server daemons (defined in StartServers) will be pre-spawned to handle page requests. Each server will handle the number of requests defined in MaxRequestsPerChild before committing suicide and causing another server to pre-fork to replace it.

        PreFork Yes

This reduces system overhead due to forking and is the fastest and best way to run a busy Interchange server. settings that will apply for all catalogs.

A yes/no directive, default is No.

46.42. Profiles *global*

Names a file (or files) which contain OrderProfile and SearchProfile settings that will apply for all catalogs.

   Profiles     etc/profiles.common

46.43. RobotIP *global*

The RobotIP directive defines a list of IP numbers which will be classed as crawler robots (search engines) and causes Interchange to alter its behavior to improve the chance of Interchange-served content being crawled and listed.

The directive accepts a wildcard list - * represents any number of characters, ? represents a single character. The elements of the list are separated by a comma.

See RobotUA for a full description of the behavioural changes.

Example:

  RobotIP   209.135.65, 64.172.5

46.44. RobotUA *global*

The RobotUA directive defines a list of User Agents which will be classed as crawler robots (search engines) and causes Interchange to alter its behavior to improve the chance of Interchange-served content being crawled and listed.

The directive accepts a wildcard list - * represents any number of characters, ? represents a single character. The elements of the list are separated by a comma.

If a User Agent is recognised as a robot, the following will be performed by Interchange:

It should be noted that once you have identified you are serving a page to a robot, you should not use this to massively alter your page content in an attempt to improve your ranking. If you do this, you stand the chance of being blacklisted. You have been warned!

Example:

  RobotUA   Inktomi, Scooter, *Robot*, *robot*, *Spider*, *spider*

See also RobotIP.

46.45. SafeUntrap *global*

Sets the codes that will be untrapped in the Safe.pm module and used for embedded Perl and conditional operations. View the Safe.pm documentation by typing perldoc Safe at the command prompt. The default is ftfile sort, which untraps the file existence test operator and the sort operator. Define it as blank to prevent any operators but the default restrictive ones.

   SafeUntrap     ftfile sort ftewrite rand

46.46. SendMailProgram *global*

Specifies the program used to send email. Defaults to '/usr/lib/sendmail'. If it is not found at startup, Interchange will return an error message and refuse to start.

   SendMailProgram     /bin/mailer

A value of 'none' will disable the sending of emailed orders. Orders must be read from a tracking file, log, or by other means.

46.47. SOAP *global*

If set to Yes, allows handling of SOAP rpc requests.

46.48. SOAP_Host *global*

The list of hosts that are allowed to connect to for SOAP rpc requests. Default is localhost 127.0.0.1.

46.49. SOAP_MaxRequests *global*

The maximum number of requests a SOAP rpc server will handle before it commits suicide and asks for a replacement server. This prevents runaway memory leaks.

46.50. SOAP_Perms *global*

The permissions that should be set on a SOAP UNIX-domain socket. Default is 0660, which allows only programs running as the same UID as Interchange to access the socket.

46.51. SOAP_Socket *global*

A list of sockets which should be monitored for SOAP requests. If they fit the form NNN.NNN.NNN.NNN:PPPP, they are IP addresses and ports for monitoring INET-domain sockets, any other pattern is assumed to be a file name for monitoring in the UNIX domain.

   SOAP_Socket 12.23.13.31:7770 1.2.3.4:7770 /var/run/interchange/soap

46.52. SOAP_StartServers *global*

The number of SOAP servers which should be started to handle SOAP requests. Default is 1.

   SOAP_StartServers   10

46.53. SocketFile *global*

The name of the file which is used for UNIX-domain socket communications. Must be in a directory where the Interchange user has write permission.

   SocketFile  /var/run/interchange/interchange.socket

Default is etc/socket or the value of the environment variable MINIVEND_SOCKET. If set, it will override the environment. It can be set on the command line as well:

   bin/interchange -r SocketFile=/tmp/interchange.socket

46.54. SocketPerms *global*

The permissions (prepend a 0 to use octal notation) that should be used for the UNIX-domain socket. Temporarily set this to 666 on the command line to debug a permission problem on vlink.

   bin/interchange -r SocketPerms=0666

46.55. StartServers *global*

The number of Interchange page servers which should be started to handle page requests when in PreFork mode. Default is 1.

   StartServers   8

46.56. SubCatalog *global*

Allows definition of a catalog which shares most of the characteristics of another catalog. Only the directives that are changed from the base catalog are added. The parameters are: 1) the catalog ID, 2) the base catalog ID, 3) the directory to use (typically the same as the base catalog), and 4) the SCRIPT_NAME that will trigger the catalog. Any additional parameters are aliases for the SCRIPT_NAME.

The main reason that this would be used would be to conserve memory in a series of stores that share most of the same pages or databases.

   SubCatalog   sample2 sample /usr/catalogs/sample /cgi-bin/sample2

46.57. SysLog *global*

Set up syslog(8) error logging for Interchange.

   SysLog  command  /usr/bin/logger
   SysLog  tag      int1
   SysLog  alert    local3.warn
   SysLog  warn     local3.info
   SysLog  info     local3.info
   SysLog  debug    local3.debug

This would cause global errors to be logged with the command:

   /usr/bin/logger -t int1 -p local3.alert

and cause system log entries something like:

   Oct 26 17:30:11 bill int1: Config 'co' at server startup
   Oct 26 17:30:11 bill int1: Config 'homefn' at server startup
   Oct 26 17:30:11 bill int1: Config 'simple' at server startup
   Oct 26 17:30:11 bill int1: Config 'test' at server startup
   Oct 26 17:30:13 bill int1: START server (2345) (INET and UNIX)

This would work in conjunction with a UNIX syslogd.conf entry of:

        # Log local3 stuff to Interchange log
        local3.*                /var/log/interchange.log

A custom wrapper can be created around it to get it to behave as desired. For instance, if you didn't want to use syslog but instead wanted to log to a database (via DBI), you could create a Perl script named "logdatabase" to log things:

    #!/usr/bin/perl

    my $script_name = "logdatabase";
    use DBI;
    use Getopt::Std;

    getopts('d:p:T:k:')
        or die "$script_name options: $@\n";

    use vars qw/$opt_d $opt_p $opt_T $opt_k/;

    my $dsn   = $opt_d || $ENV{DBI_DSN};
    my $template = $opt_T
        || "insert into log values ('~~KEY~~', '~~LEVEL~~', '~~MSG~~')";

    my $dbh = DBI->connect($dsn)
        or die "$script_name cannot connect to DBI: $DBI::errstr\n";

    my %data;

    $data{KEY} = $opt_k || '';

    local ($/);
    $data{MSG} = <>;

    $data{LEVEL} = $opt_p || 'interchange.info';

    $template =~ s/\~\~(\w+)\~\~/$dbh->quote($data{$1})/;

    my $sth = $dbh->prepare($template)
        or die "$script_name error executing query: $template\n";

    $sth->execute()
        or die "$script_name error executing query: $template\n";

    exit;

46.58. TagDir *global*

Defines the directory or directories that Interchange will scan for tag, filter, widget, and other code declarations.

   TagDir  code etc/other_code

Relative to the Interchange software root. Default is code.

46.59. TagGroup *global*

Defines a group of tags for possible inclusion or exclusion in the set of ITL tags Interchange will compile and use.

TagGroup :file "counter file include log value_extended"
EOF

Default is defined in lib/Vend/Config.pm, and is too lengthy to show here. Above is the default :file group.

46.60. TagInclude *global*

Includes or excludes a set of IC tags for compilation and use. The TagDir is scanned for files, and when found they are checked against tag names and the groups defined in .TagGroup.

TagInclude ALL !:crufty !get_url

The above will include all tags by default, but not the group :crufty nor the tag get_url.

Default is ALL.

46.61. TcpHost *global*

When running in INET mode, using tlink, specifies the hosts that are allowed to send/receive transactions from any catalog on this Interchange server. Can be either an name or IP number, and multiple hosts can be specified in a space-separated list. Default is localhost.

   TcpHost         localhost secure.domain.com

46.62. TcpMap *global*

When running in INET mode, using tlink or the internal HTTP server, specifies the port(s) which will be monitored by the Interchange server. Default is 7786.

To use the internal HTTP server (perhaps only for password-protected queries), a catalog may be mapped to a port. If three catalogs were running on the server www.akopia.com, named simple, sample, and search, the directive might look like this:

   TcpMap    7786 -  7787 simple 7788 sample 7789 search


Note: To map large numbers of ports, use the <<MARKER here document notation in interchange.cfg. With this in effect, the internal HTTP server would map the following addresses:

   *:7786   mv_admin
   *:7787   simple
   *:7788   sample
   *:7789   search


Note: This does not pertain to the use of tlink, which still relies on the CGI SCRIPT_PATH. To enable this, the SCRIPT_PATH aliases /simple, /sample, etc. must be set in the Catalog directive. This would look like:

 Catalog  simple  /home/interchange/catalogs/simple /cgi-bin/simple /simple

To bind to specific IP addresses, add them in the same fashion that they would as an Apache Listen directive:

   TcpMap <<EOF
       127.0.0.1:7786       -
       www.akopia.com:7787  -
   EOF


Note: As usual, the EOF should be at the beginning of a line with no leading or trailing whitespace.

46.63. TemplateDir *global*

This can be used to supply some default pages so catalogs will not need their own copies.

Supply one or more directory names, separated by whitespace, which will be searched for pages not found in the catalog's PageDir directory or the catalog-level TemplateDir directory list.

   TemplateDir    /usr/local/interchange/default_pages

This is undefined by default.

46.64. TolerateGet *global*

Set to 'Yes' to enable parsing of both GET data and POST data when a POST has been submitted. The default is 'No', which means that GET data is ignored during a POST. Unfortunately this has to be a global setting because at URL parse time, the Interchange daemon doesn't yet know which catalog it's dealing with (due to catalog aliases, etc.).

46.65. TrustProxy *global*

Allows the administrator to designate certain IP addresses or hostnames as trusted HTTP proxies, whose claims (via the HTTP_X_FORWARDED_FOR environment variable set by the web server) about the original requesting host will be assumed accurate.

When using a front-end proxy for Interchange, all requests appear to come from that proxy, for example, perhaps 127.0.0.1 if on the same machine. This is effectively the same as running with WideOpen Yes, because all sessions will have the same user IP address and thus can be easily hijacked. Session hijacking can happen when someone unknowingly includes a session ID in a URL they send to other users, and all those users then end up with the same session and shopping cart!

TrustProxy takes a comma-separated list of one or more IP addresses and/or hostnames, which may include wildcards (* for any number of characters, ? for a single character). For example:

TrustProxy 127.0.0.1, 10.0.0.*

I'm not sure why anyone would want to do this, but it could also be used with external HTTP proxies in general (which you can only hope aren't lying), with a simple 'TrustProxy *'.

Note that the environment variables are not modified in any way; only Interchange's idea of the remote host is altered, as you see with [data session host].

46.66. UrlSepChar *global*

Sets the character which separates form parameters in Interchange-generated URLs. Default is &.

46.67. Unix_Mode *global*

Determines whether the UNIX-domain socket will be monitored on startup. Overridden by the command-line parameter -u. Default is Yes.

46.68. UserTag *global*

This defines a UserTag which is global in nature, meaning not limited by the Safe.pm module, and is is available to all Interchange catalogs running on the server. Otherwise, this is the same as a catalog UserTag.

46.69. Variable *global*

Defines a global variable that will be available in all catalogs with the notation @@VARIABLE@@. Variable identifiers must begin with a capital letter, and can contain only word characters (A-Z,a-z,0-9 and underscore). They are case-sensitive.

   Variable   DOCUMENT_ROOT   /usr/local/etc/httpd/htdocs

Only variables with ALL CAPS names will be parsed in catalog pages or, when the ParseVariables directive is set, in catalog (not global) configuration directives (other than Variable itself). These are substituted first in any Interchange page, and can contain any valid Interchange tags including catalog variables. If a variable is called with the notation @_VARIABLE_@, and there is no catalog Variable with its name, the global Variable value will be inserted.

There are several standard variables which you should not set:

MV_FILE

MV_NO_CRYPT

MV_PAGE

CURRENCY, MV_CURRENCY

LANG, MV_LANG

Some global variables can be set to affect Interchange:

MV_DOLLAR_ZERO

Setting Result
(not set) 'interchange'
0 (do nothing)
1 'interchange --> (CATROOT)'
string 'string'

46.70. VarName *global*

Sets the names of variables that will be remapped to and from the URL when Interchange writes it. For instance, to display the variable mv_session_id as session in the user's URL:

   VarName   mv_session_id  session

The default can also be set in the etc/varnames file after the first time Interchange is run. Setting it in interchange.cfg is probably better for clarity.

There is also a catalog-specific version of this setting.

47. catalog.cfg

Each catalog must have a catalog.cfg file located in its base catalog directory. It contains most of the configurable parameters for Interchange. Each is independent from catalog to catalog.

Additional configuration techniques are available in the catalog.cfg file. First, set a Variable and use its results in a subsequent configuration setting if ParseVariables is on:

   Variable   SERVER_NAME  www.akopia.com
   Variable   CGI_URL      /cgi-bin/demo

   ParseVariables Yes
   VendURL    http://__SERVER_NAME____CGI_URL__
   ParseVariables No

Define subroutine watches

47.1. Programming Watch Points in catalog.cfg

Almost any configuration variable can be set up to be tied to a subroutine if the Tie::Watch module installed. It uses a notation like the <<HERE document, but <&HERE is the notation. Here is a simple case:

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

When the order is mailed out, if the user has a variable called special_handling set in their session (from UserDB, perhaps), the order will be sent to 'vip@akopia.com.' Note the single quotes to prevent problems with the @ sign. Otherwise, the order will get sent to the previously defined value of orders@akopia.com.

If the configuration value being watched is a SCALAR, the subroutine gets the following call:

   &{$subref}(SELF, PREVIOUS_VALUE)

The subroutine should simply return the proper value.

SELF is a reference to the Tie::Watch object (read its documentation for what all it can do) and PREVIOUS_VALUE is the previously set value for the directive. If set after the watch is set up, it will simply have the effect of destroying the watch and having unpredictable effects. (In the future, a "Store" routine may be able to be set up that can subsequently set values).

If the configuration value being watched is an ARRAY, the subroutine gets the following call:

   &{$subref}(SELF, INDEX, PREVIOUS_VALUE)

INDEX is the index of the array element being accessed. Setting up watch points on array values is not recommended. Most Interchange subroutines call arrays in their list context, and no access method is provided for that.

If the configuration value being watched is a HASH, the subroutine gets the following call:

   &{$subref}(SELF, KEY, PREVIOUS_VALUE)

KEY is the index into the hash, an example of HASH type Interchange configuration values. NOTE: The following is not recommended for performance reasons. The Variable is a commonly used thing and should not bear the extra overhead of tieing, 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->{name}";
           }
       }
       else {
           return $orig->{$key};
       }
   }
   EOV

The first time __TESTIT__ is called for a particular user, it will return the string "Tie::Watch works! -- name=" along with their name set in the session (if that exists). Any other variables will receive the value that they were set to previously. Once the TESTIT key has been accessed for that user, the watch is dropped upon the next access.

47.2. Configuration Directives in catalog.cfg

All directives except MailOrderTo and VendURL have default values and are optional, though most catalogs will want to configure some of them.

47.3. ActionMap

Allows setting of Interchange actions, usually with a Perl subroutine. Actions are page names like:

process  Perform a processing function
order    Order items
scan     Search based on path info
search   Search based on submitted form variables

These are the standard supplied actions for Interchange. They can be overwritten with user-defined versions if desired. For example, to ignore the order action, set:

   ActionMap  order  sub { return 1 }

When the leading part of the incoming path is equal to order, it will trigger an action. The page name will be shifted up, and the order stripped from the page name. So this custom order action would essentially perform a no-op, and a URL like:

   <A HREF="[area order/nextpage]"> Go to the next page </A>

would be the equivalent of "[area nextpage]." If the action does not return a true (non-zero, non-blank) status, no page will be displayed by Interchange, not even the special missing page. A response may also be generated via Perl or MVASP.

The standard process action has a number of associated FormAction settings. Besides using Perl, Interchange tags may be used in an action, though they are not nearly as efficient.

47.4. AlwaysSecure

Determines whether checkout page operations should always be secure. Set it to the pages that should always be secure, separated by spaces and/or tabs.

   AlwaysSecure    ord/checkout

47.5. AsciiTrack

A file name to log formatted orders in. Unless preceded by a leading '/', will be placed relative to the catalog directory. Disabled by default.

   AsciiTrack     etc/tracking.asc

If a Route is set up to supplant, this is ignored.

47.6. AutoEnd

Sets an action that is automatically performed at the end of every access. It is performed after any page parsing occurs, just before the transaction ends. It takes the same kinds of parameters as Autoload.

47.7. Autoload

Sets an action that is automatically performed for every access. It is performed before any page parsing occurs, and before the action or page is even determined. It can be set to a string containing ITL tags or to the name of a catalog (Sub) or global subroutine. The return value from the code run is discarded.

For example, to automatically run the Sub or GlobalSub named 'testsub':

   Autoload testsub

To remap any mv_nextpage accesses to the private subdirectory of pages, set:

   Autoload   [perl] $CGI->{mv_nextpage} =~ s:^private/:public/:; [/perl]

You can temporarily change any of the catalog configuration settings, for example, to use a different flypage depending on the user's browser type:

   Autoload       <<EOA
   [perl]
   if ($Session->{browser} =~ /msie/i) {
      $Config->{Special}->{flypage} = 'ie_flypage';
   }
   [/perl]
   EOA

Please note that SpecialPage is the corresponding directive in the catalog configuration, not Special. This is an exceptional case. Usually the hash key has the same name as the catalog configuration directive.

47.8. AutoModifier

Sets an attribute in a shopping cart entry to the field of the same name in the ProductsFile pertaining to this item. This is useful when doing shipping calculations or other embedded Perl that is based on item attributes. To set whether an item is defined as "heavy" and requires truck shipment, set:

   AutoModifier  heavy

When an item is added to the shopping cart using Interchange's routines, the heavy attribute will be set to the value of the heavy field in the products database. In the default demo that would be products. Any changes to ProductFiles would affect that, of course.

Some values are used by Interchange and are not legal:

       mv_mi
       mv_si
       mv_ib
       group
       code
       quantity
       item

47.9. AutoVariable

Specifies directives which should be translated to Variable settings. For scalars, the directive name becomes the Variable name and yields its value, i.e. DescriptionField becomes __DescriptionField__, which would by default be description. Array variables have a _N added, where _N is the ordinal index, i.e. ProductFiles becomes __ProductFiles_0__, __ProductFiles_1__, etc. Hash variables have a _KEY added, i.e. SpecialPage becomes __SpecialPage_missing__, __SpecialPage_violation__, etc. Doesn't handle hash keys that have non-word characters or whitespace. Only single-level arrays and hashes are translated properly.

47.10. CommonAdjust

Settings for Interchange pricing. See Chained pricing.

   CommonAdjust    pricing:q2,q5,q10,q25, ;products:price, ==size:pricing

47.11. ConfigDir

The default directory where directive values will be read from when using the <file notation. Default is config. The name is relative to the catalog directory unless preceded by a /.

   ConfigDir      variables

This can be changed several times in the catalog.cfg file to pick up values from more than one directory. Another possibility is to use a Variable setting to use different templates based on a setting:

   Variable   TEMPLATE   blue

   ParseVariables Yes
   ConfigDir  templates/__TEMPLATE__
   ParseVariables No
   Variable   MENUBAR   <menubar
   Variable   LEFTSIDE  <leftside
   Variable   BOTTOM    <bottom
   ConfigDir config

This will pick the templates/blue template. If TEMPLATE is set to red, it would read the variables from templates/red.

47.12. CookieDomain

Allows a domain to be set so that multiple servers can handle traffic. For example, to use server addresses of secure.yourdomain.com and www.yourdomain.com, set it to:

   CookieDomain    .yourdomain.com

More than one domain can be set. It must have at least two periods or browsers will ignore it.

47.13. CookieLogin

Allows users to save their username/password (for Vend::UserDB) in a cookie. Expiration is set by SaveExpire and is renewed each time they log in. To cause the cookie to be generated originally, the CGI variable mv_cookie_password or mv_cookie_username must be set. The former causes both username and password to be saved; the latter just the username.

   CookieLogin  Yes

Default is No.

47.14. Cookies

Determines whether Interchange will send (and read back) a cookie to get the session ID for links that go outside the catalog. Allows arbitrary HREF links to be placed in Interchange pages, while still saving the contents of the session. The default is Yes.

   Cookies         Yes

If the Cookies directive is enabled, and mv_save_session is set upon submission of a user form (or in the CGI variables through a Perl GlobalSub), the cookie will be persistent for the period defined by SaveExpire.


Note: This should almost always be "Yes."

Caching, timed builds, and static page building will never be in effect unless this directive is enabled.

47.15. CreditCardAuto

If set to Yes, enables the automatic encryption and saving of credit card information. In order for this to work properly, the EncryptProgram directive must be set to properly encode the field. The best way to set EncryptProgram is with PGP in the ASCII armor mode. This option uses the following standard fields on Interchange order processing forms:

mv_credit_card_number

mv_credit_card_exp_all

mv_credit_card_exp_month

mv_credit_card_exp_year

mv_credit_card_error

mv_credit_card_force

mv_credit_card_separate

mv_credit_card_info

mv_credit_card_valid

GnuPG is recommended as the encryption program. Interchange will also work with PGP.

   CreditCardAuto     Yes

47.16. Cron *5.0 and up*

Configuration for jobs run with the --cron commandline option.

base_directory, use_global

Directory to search for cron jobs. The default is etc/cron in the catalog directory. If use_global is set, the same directory is searched in the global configuration directory.

initialize, autoload

The macros initialize and autoload are executed once resp. before each job.

email, log, add_session

The output of a single run of cron jobs is written to a log file and send by email if the corresponding configuration values email and log are set. An email address passed by the commandline option --email has higher preference than the email address in email.

If the run produces no output, neither the email will be send nor the log file entry will be written.

add_session adds the current session to the output.

from, subject, reply_to, extra_headers

Additional configuration values for the generation of the email.

47.17. CustomShipping

If not blank, causes an error log entry if the shipping file entry is not found. Not otherwise used for shipping. See SHIPPING for how to go about doing that.

   CustomShipping      Yes

47.18. Database

Definition of an arbitrary database, in the form "Database database file type," where "file" is the name of an ASCII file in the same format as the products database. The file is relative to VendRoot. Records can be accessed with the [data database field key] tag. Database names are restricted to the alphanumeric characters (including the underscore), and it is recommended that they be either all lower or all upper case. See DATABASES.

   Database      reviews  reviews.txt  CSV

47.19. DatabaseDefault

Defines default parameters for a database. This can be used to set a default WRITE_CONTROL setting, set a default USER or PASSWORD, etc. It accepts any scalar setting, which means all except:

ALTERNATE_* BINARY COLUMN_DEF DEFAULT FIELD_ALIAS FILTER_* NAME NUMERIC POSTCREATE WRITE_CATALOG

This default setting is made when the table is initially defined, i.e. explicit settings for the database itself override the defaults set.

   DatabaseDefault      WRITE_CONTROL   1
   DatabaseDefault      WRITE_TAGGED    1

This setting must be made *before* the database is defined. To reset its value to empty, use the Replace directive.

   Replace DatabaseDefault

47.20. DefaultShipping

This sets the default shipping mode by initializing the variable mv_ship_mode. If not set in catalog.cfg, it is default.

   DefaultShipping     UPS

Somewhat deprecated, the same thing can be achieved with:

   ValuesDefault   mv_shipmode UPS

47.21. DescriptionField

The field that will be accessed with the [item-description] element.

   DescriptionField    description

Default is description. It is not a fatal error if this field does not exist. This is especially important for on-the-fly items. If there is an attribute set to the same name as DescriptionField, this will be used for display.

47.22. DirConfig

DirConfig allows you to batch-set a bunch of variables from files. The syntax:

DirConfig directive-name directory-glob

directive-name is usually Variable, but could be any hash-based directive. (No other standard directives currently make sense to set this way.)

directory-glob is a filespec that could encompass multiple directories. Files are ignored.

The directories are read for file *names* that contain only word characters, i.e. something that would be a valid Variable. (This alone might make it not suitable for other uses, but picking up the junk from the in-directory-backup-file people would be intolerable.)

Then the contents of the file is used to set the variable of the file name.

The source file name is kept in $Vend::Cfg->{DirConfig}{Variable}{VARNAME}, for use if dynamic_variables Pragma is set.

Pragma dynamic_variables enables dynamic updating of variables from files. Pragma dynamic_variables_files_only restricts dynamic variables to files only -- otherwise variables are dynamically read from the VarDatabase definition as well.

With dynamic variables, all @_VARIABLE_@ and __VARIABLE__ settings are checked first to see if the source file is defined. If there is a key present, even if its contents are blank, it is returned. Example -- in the case of this catalog.cfg entry:

        DirConfig Variable templates/foundation/regions

If the file NOLEFT_TOP is present at catalog config time, __NOLEFT_TOP__ will equal [include templates/foundation/regions/NOLEFT_TOP].

47.23. DirectoryIndex

If DirectoryIndex is set, and a page would normally be defined as missing, it's value is appended (with a separating / if appropriate) and the resulting page is looked for. To get the behavior normally associated with an HTTP server, where "index.html" is looked for in a directory, do:

        DirectoryIndex   index.html

Default is blank, disabling the behavior.

47.24. DisplayErrors

If the administrator has enabled DisplayErrors globally, setting this to "Yes" will display the error returned from Interchange in case something is wrong with embedded Perl programs, tags, or Interchange itself. Usually, this will be used during development or debugging. Default is No.

   DisplayErrors       Yes

47.25. DynamicData

When set to one or more Interchange database identifiers, any pages using data items from the specified database(s) will not be cached or built statically. This allows dynamic updating of certain arbitrary databases (even the products database) while still allowing static/cached page performance gains on pages not using those data items.

   DynamicData         inventory

Overridden by [tag flag build][/tag], depending on context.

47.26. EncryptProgram

Contains a program command line specification that indicates how an external encryption program will work. Two placeholders, %p and %f, are defined, which are replaced at encryption time with the password and temporary file name respectively. See Order Security. This is separate from the PGP directive, which enables PGP encryption of the entire order.

If PGP is the encryption program (Interchange determines this by searching for the string pgp in the command string), no password field or file field need be used. The field mv_credit_card_number will never be written to disk in this case.

   EncryptProgram      /usr/local/bin/pgp -feat sales@company.com

If the order Route method of sending orders is used (default in the demo), this sets the default value of the encrypt_program attribute.

47.27. ErrorFile

This is where Interchange will write its runtime errors for THIS CATALOG ONLY. It can be shared with other catalogs or the main Interchange error log, but if it is root-based, permission to write the file is required.

   ErrorFile   /home/interchange/error.log

47.28. ExtraSecure

Disallows access to pages which are marked with AlwaysSecure unless the browser is in HTTPS mode. A Yes/No directive, the default is 'No.'

   ExtraSecure  Yes

47.29. Filter

Assigns one or more filters (comma separated) to be automatically applied to a variable.

As an example, multiple form variable submissions on the same page come back null-separated, like 'value1\0value2\0value3'. To automatically change those nulls to spaces, you could use this directive:

Filter  mail_list  null_to_space

Of course you could just as easily use the [filter] tag on the page if the filter is only going to be used in a few places. See the [filter] tag documentation (wiki FilterTag) for more information and a list of filters.

47.30. FormAction

Allows set up of a form action (like the standard ones return, submit, refresh, etc.). It requires a Perl subroutine as a target:

   FormAction foo <<EOR
   sub {
       $CGI->{mv_nextpage} = 'bar';
   }
   EOR

If it returns a true (non-zero, non-empty) value, Interchange will display the page defined in $CGI->{mv_nextpage}. Otherwise, Interchange will not display any page. The default Interchange actions can be overridden if desired. There is also a global version of this directive, which is overridden if a catalog-specific action exists.

47.31. FormIgnore

Set to the name(s) of variables that should not be carried in the user session values. Must match exactly and are case sensitive.

   FormIgnore    mv_searchtype

47.32. FractionalItems

Whether the quantity field for items in the shopping cart should be allowed to be fractional, i.e., 2.5 or 1.25. Default is No.

   FractionalItems     Yes

47.33. Glimpse

The pathname for the glimpse command, used if glimpse searches are to be enabled. To use glimpseserver, the -C, -J, and -K tags must be used.

   Glimpse  /usr/local/bin/glimpse -C -J srch_engine -K2345

47.34. History

How many of the most recent user clicks should be stored in the session history. Default is 0.

47.35. HTMLsuffix

The file extension that will be seen as a page in the pages directory. Default is .html.

   HTMLsuffix .htm

47.36. ImageAlias

Aliases for images, ala Apache/NCSA, ScriptAlias, and Alias directives. Relocates images based in a particular directory to another for Interchange use; operates after ImageDir. Useful for editing Interchange pages with an HTML editor. Default is blank.

   ImageAlias  /images/  /thiscatalog/images/

47.37. ImageDir

The directory where all relative IMG and INPUT source file specifications are based. IT MUST HAVE A TRAILING / TO WORK. If the images are to be in the DocumentRoot (of the HTTP server or virtual server) subdirectory images, for example, use the ImageDir specification '/images/'. This would change SRC="order.gif" to SRC="/images/order.gif" in IMG and INPUT tags. It has no effect on other SRC tags.

   ImageDir /images/

Can be set in the Locale settings to allow different image sets for different locales (MV3.07 and up).

47.38. ImageDirInternal

A value for ImageDir only when the internal HTTP server is in use. It must have a trailing / to work, and should always begin with a fully-qualified path starting with http://.

   ImageDirInternal http://www.server.name/images/

47.39. ImageDirSecure

A value for ImageDir only when the pages are being served via HTTPS. It must have a trailing / to work, and should always begin with a fully-qualified path starting with http://.

   ImageDirSecure   /secure/images/

This is useful if using separate HTTPS and HTTP servers, and cannot make the image directory path heads match.

47.40. Locale

Sets the special locale array. Tries to use POSIX setlocale based on the value of itself, then tries to accept a custom setting with the proper definitions of mon_decimal_point, thousands_sep, and frac_digits, which are the the only international settings required. Default, if not set, is to use US-English settings.

Example of the custom setting:

   Locale     custom mon_decimal_point , mon_thousands_sep . frac_digits 0

Example of POSIX setlocale for France, if properly aliased:

   Locale     fr

See setlocale(3) for more information. If embedded Perl code is used to sort search returns, the setlocale() will carry through to string collation.

See Internationalization.

47.41. LocaleDatabase

Set to the Interchange database identifier of a table that contains Locale settings. These settings add on to and overwrite any that are set in the catalog configuration files, including any include files.

   Database       locale  locale.asc  TAB
   LocaleDatabase locale

47.42. MailOrderTo

Specifies the e-mail address to mail completed orders to.

       MailOrderTo  orders@xyzcorp.com

If 'none' is specified, no e-mailed order will be sent.

47.43. NoCache

The names of Interchange pages that are not to be built statically if STATIC PAGE BUILDING is in use. If the name is a directory, no pages in that directory (or any below it) will be cached or built statically.

   NoCache    ord
   NoCache    special

47.44. NoImport

When set to one or more Interchange database identifiers, those database(s) will never be subject to import. Normally, Interchange checks to see if each database needs to be created and populated (from the source text file) when the Interchange daemon is started or restarted, or a catalog is reconfigured.

This is useful for SQL databases used by other applications besides Interchange, or large databases you load and back up outside of Interchange. With this option you can omit the source text file for SQL databases entirely.

   NoImport   inventory

47.45. NoImportExternal

When set to true, this directive prevents database imports for all "external" databases:

   NoImportExternal  Yes

External database types are DBI (all popular SQL databases) and LDAP. Internal database types are the DBM variants (GDBM, DB_File, SDBM) and in-memory databases.

The default setting is false (databases may be imported).

47.46. NonTaxableField

The name of the field in the products database that is set (to 1 or Yes) if an item is not to be taxed. Interchange will log an error and tax it anyway if the field doesn't exist in the database. Blank by default, disabling the feature.

   NonTaxableField    wholesale

47.47. NoSearch

Here you can provide one or more filename fragments that will be matched against the file name used in any attempted search (the mv_search_file or 'fi' attribute). You may separate multiple match strings with whitespace, and may include shell-style wildcards.

The default setting is 'userdb', which means that by default you cannot use Interchange-style searches on the userdb table. (Pure SQL searches still work with it, however.)

For example, consider this setting:

   NoSearch  userdb  .*  *.secret

In this case any search file with 'userdb' in its name, or beginning with a dot, or ending in '.secret', will not be searchable.

47.48. OfflineDir

The location of the offline database files for use with the Interchange offline database build command. Set to "offline" as the default, and is relative to VendRoot if there is no leading slash.

   OfflineDir          /usr/data/interchange/offline

47.49. OnFly

Enables on-the-fly item additions to the shopping cart. If set to the name of a valid UserTag, that tag definition will be used to parse and format the item with the following call:

   $item = Vend::Parse::do_tag($Vend::Cfg->{OnFly},
                                   $code,
                                   $quantity,
                                   $fly[$j],
                               );

$fly[$j] is the value of mv_order_fly for that item. A default onfly tag is provided by Interchange. For more information, see the section that describes how to set up an on-the-fly item.

47.50. OrderCounter

The name of the file (relative to catalog root if no leading /) that maintains the order number counter. If not set, the order will be assigned a string based on the time of the order and the user's session number.

   OrderCounter       etc/order.number

Bear in mind that Interchange provides the order number as a convenience for display, and that no internal functions depend on it. Custom order number routines may be defined and used without fear of consequences.

If a Route is set up to supplant and the counter attribute is set there, this is ignored.

47.51. OrderLineLimit

The number of items that the user is allowed to place in the shopping cart. Some poorly-mannered robots may "attack" a site by following all links one after another. Some even ignore any robots.txt file that may have been created. If one of these bad robots orders several dozen or more items, the time required to save and restore the shopping cart from the user session may become excessive.

If the limit is exceeded, the command defined in the Global directive LockoutCommand will be executed and the shopping cart will be emptied. The default is 0, disabling the check. Set it to a number greater than the number of line items a user is ever expected to order.

   OrderLineLimit   50

47.52. OrderProfile

Allows an unlimited number of profiles to be set up, specifying complex checks to be performed at each of the steps in the checkout process. The files specified can be located anywhere. If relative paths are used, they are relative to the catalog root directory.

   OrderProfile    etc/profiles.order etc/profiles.login

The actions defined here are also used for mv_click actions if there is no action defined in scratch space. They are accessed by setting the mv_order_profile variable to the name of the order profile. Multiple profiles can reside in the same file, if separated by __END__ tokens, which must be on a line by themselves.

The profile is named by placing a name following a __NAME__ pragma:

 __NAME__ billing

The __NAME__ must begin the line, and be followed by whitespace and the name. The search profile can then be accessed by <mv_order_profile="billing">. See Advanced Multi-level Order Pages.

47.53. OrderReport

The location of the simple order report file. Defaults to etc/report.

   OrderReport          /data/order-form

47.54. PageDir

Location of catalog pages. Defaults to the pages subdirectory in the VendRoot directory.

   PageDir    /data/catalog/pages

Can be set in the Locale settings to allow different page sets for different locales.

47.55. PageSelectField

Sets a products database column which can be used to select the on-the-fly template page. This allows multiple on-the-fly pages to be defined. If the field is empty (no spaces), the default flypage will be used.

   PageSelectField    display_page

47.56. ParseVariables

Determines whether global and catalog variables will be parsed in catalog configuration directives (not including the Variable directive itself, which never parses its settings). Applies only to variables with names in ALL CAPS. Default setting is No. The foundation catalog.cfg turns ParseVariables on and usually expects it to be on.

   Variable STORE_ID  topshop
   ParseVariables Yes
   StaticDir  /home/__STORE_ID__/www/cat
   ParseVariables No

47.57. Password

The encrypted or unencrypted password (depending on Variable MV_NO_CRYPT) that will cause internal authorization checks for RemoteUser to allow access.

Below is the encrypted setting for a blank password.

   Password                bAWoVkuzphOX.

47.58. PGP

If credit card information is to be accepted, and the e-mailed order will go over an insecure network to reach its destination, PGP security should be used. The key ring to be used must be for the user that is running the Interchange server, or defined by the environment variable PGPPATH, and the key user specified must have a key on the public key ring of that user.

   PGP        /usr/local/bin/pgp -feat orders@company.com

If this directive is non-null, the PGP command string as specified will be used to encrypt the entire order in addition to any encryption done as a result if CreditCardAuto. If, for some reason, an error comes from PGP, the customer will be given the special page failed.

If a Route is set up to supplant, this is ignored.

47.59. Pragma

Sets the default value of an Interchange pragma. The directive is set like this:

   Pragma my_pragma_name

To enable a pragma for only a particular page, set it anywhere in the page:

   [pragma my_pragma_name]

To disable a pragma for a particular page, set it anywhere in the page:

   [pragma my_pragma_name 0]

Descriptions of each pragma follow.

dynamic_variables

dynamic_variables_file_only

init_page

Defines a Sub or GlobalSub which will run before page Variable processing. A *reference* to the contents of the page is passed to the routine.

For instance, if a page was found that did not have a @_VARIABLE_@ in it, you could wrap it with a template:

    Pragma  init_page=wrap_page
        Sub <<EOS
        sub wrap_page {
                my $pref = shift;
                return if $$pref =~ m{\@_[A-Z]\w+_\@};
                $$pref =~ m{<!--+ title:\s*(.*?)\s+-->}
                        and $Scratch->{page_title} = $1;
                $$pref = <<EOF;
        \@_MYTEMPLATE_TOP_\@
        <!--BEGIN CONTENT -->
        $$pref
        <!-- END CONTENT -->
        \@_MYTEMPLATE_BOTTOM_\@
        EOF

                return;
        }
        EOS

post_page

Defines a Sub or GlobalSub which will run after page Variable processing but before tag interpolation. A

Example -- you want your users to be able to edit pages and just put in <A href="someotherpage.html">. You can use post_page to handle this. To do so, put in catalog.cfg:

  Pragma   post_page=relative_urls

  ### Take hrefs like <A HREF="about.html"> and make relative to current
  ### directory
  Sub <<EOR
  sub relative_urls {
      my $page = shift;
      my @dirs = split "/", $Tag->var('MV_PAGE', 1);
      pop @dirs;
      my $basedir = join  "/", @dirs;
      $basedir ||= '';
      $basedir .= '/' if $basedir;

      my $sub = sub {
          my ($entire, $pre, $url) = @_;
          return $entire if $url =~ /^\w+:/;
          my($page, $form) = split /\?/, $url, 2;
          my $u = $Tag->area({
                    href => "$basedir$page",
                    form => $form,
                });
          return qq{$pre"$u"};
      };
      $$page =~ s{
              (
                  (
                  <a \s+ (?:[^>]+?\s+)?
                      href \s*=\s*
                  )
                      (["']) ([^\s"'>]+) \3

              )}
              {
                  $sub->($1,$2,$4)
              }gsiex;
      return;
  }
  EOR

pre_page

Defines a Sub or GlobalSub which will run after page Variable processing but before tag interpolation. A

no_image_rewrite

Prevents image locations in pages from being altered by Interchange. Added in Interchange 4.7.0.

Interchange normally rewrites image locations to point to ImageDir. This applies to image locations mentioned in <img src="...">, <input src="...">, <body background="...">, <table background="...">, and <tr/th/td background="...">.

When this pragma is not set, the following tag:

   <img src="fancy.gif">

Would, assuming an ImageDir set to /foundation/images, be transformed into:

   <img src="/foundation/images/fancy.gif">

When pragma no_image_rewrite is set, the <img> tag would remain unchanged.

safe_data

By default Interchange does not allow data returned from databases to be reparsed for Interchange tags. Setting the safe_data pragma eliminates this restriction.

If for some reason you want to have tags in your database, for example, to use [page ...] for catalog-internal hyperlinks in your product descriptions, you need to enable safe_data. Some things to consider:

  1. It may be better to use the safe_data attribute available to certain tags instead of the pragma, or perhaps to use [pragma] for a whole page or [tag pragma] ... [/tag] for a small block, instead of a catalog-wide Pragma directive.
  2. In any case it is strongly recommended that you surround the area with [restrict] ... [/restrict] tags to allow only the specific (hopefully relatively safe) set of tags you expect to appear, such as [page] or [area]. Expect security compromises if you allow [calc] or [perl], or other extremely powerful tags.
  3. Be certain that you know everywhere the data in your database will be used. Will it always be possible to reparse for tags? What about when it's used to create an emailed plain-text receipt -- will a literal '[page ...]' tag show up in the product description on the receipt? Would the desired output of '<a href="...">' be any better in a plaintext situation? What if you access your database from applications other than Interchange? You'll then have to decide what to do with such tags; perhaps you can simply strip them, but will the missing tag output cause you any trouble?

In short, safe_data is disabled by default for a reason, and you should be very careful if you decide to enable it.

(Watch out for parse order with [tag pragma] or [restrict] when used with lists that retrieve data from the database, as in [PREFIX-*] and the flypage. Loops parse before regular tags like [tag] and [restrict], and thus aren't affected by it.)

strip_white

Set this to strip whitespace from the tops of HTML pages output by Interchange. Such whitespace usually comes from Interchange tags at the top of the page. The pragma's purpose is mostly to make 'view source' in the browser a slightly more tolerable experience.

Default is off; whitespace is unchanged.

47.60. PriceCommas

If no commas are desired in price numbers (for the [item-price] tag), set this to No. The default is to use commas (or whatever is the thousands separator for a locale).

   PriceCommas         no

This is overridden if a Locale price_picture is set.

47.61. PriceDivide

The number the price should be divided by to get the price in units (dollars or such). The default is one. If penny pricing is used, set it to 100.

   PriceDivide         100

Can be set in the Locale settings to allow a price adjustment factor for different currencies.

47.62. PriceField

The field in the product database that will be accessed with the [item-price] element. Default is "price."

   PriceField          ProductPrice

Can be set in the Locale settings to allow different price fields for different currencies.

47.63. ProductDir

Location of the database files. Defaults to the products subdirectory of the VendRoot directory. May not be set to an absolute directory unless NoAbsolute is defined as No.

   ProductDir          /data/catalog/for-sale

Most people never set this directive and use the default of products.

47.64. ProductFiles

Database tables that should be seen as the "products" database.

   ProductFiles    vendor_a vendor_b

The key thing about this is that each will be searched in sequence for a product code to order or an [item-field ....] or [loop-field ...] to insert. The main difference between [item-field ....] and [item-data table ...] is this fall-through behavior.

Default is products.

47.65. ReadPermission and WritePermission

By default, only the user account that Interchange runs under (as set by the SETUID permission on vlink) can read and write files created by Interchange. WritePermission and ReadPermission can be set to user, group, or 'world'.

   ReadPermission      group
   WritePermission     group

47.66. RemoteUser

The value of the HTTP environment variable REMOTE_USER that will enable catalog reconfiguration. HTTP basic authentication must be enabled for this to work. Default is blank, disabling this check.

   RemoteUser   interchange

47.67. Replace

Causes a directive to be emptied and re-set (to its default if no value is specified). Useful for directives that add to the value by default.

   Replace NoCache ord special multi reconfig query

Capitalization must be exact on each directive.

47.68. Require

Forces a Perl module, global UserTag, or GlobalSub to be present before the catalog will configure. This is useful when transporting catalogs to make sure they will have all needed facilities.

   Require usertag   email
   Require globalsub form_mail
   Require module    Business::UPS

47.69. RobotLimit

The RobotLimit directive defines the number of consecutive pages a user session may access without a 30 second pause. If the limit is exceeded, the command defined in the Global directive LockoutCommand will be executed and catalog URLs will be rewritten with host 127.0.0.1, sending the robot back to itself. The default is 0, disabling the check.

   RobotLimit  200

47.70. Route

Sets up order routes. See Custom Order Routing. There are examples in the demo simple.

47.71. SalesTax

If non-blank, enables automatic addition of sales tax based on the order form. The value is one of three types of values:

multi

[itl-tags]

var1, var2

       SalesTax            zip state

47.72. SalesTaxFunction

A Perl subroutine that will return a hash reference with the sales tax settings. This can be used to query a database for the tax for a particular vendor:

   SalesTaxFunction  <<EOR
         my $vendor_id = $Session->{source};
       my $tax = $TextSearch->hash( {
                           se => $vendor_id,
                           fi => 'salestax.asc',
                           sf => 'vendor_code',
                           ml => 1000,
                           } );
       $tax = {} if ! $tax;
       $tax->{DEFAULT} = 0.0;
       return $tax;
   EOR

or simply produce a table:

   SalesTaxFunction  <<EOR
    return {
        DEFAULT => 0.0,
        IL => 0.075,
        OH => 0.065,
    };
EOR

A DEFAULT value must always be returned or the function will be ignored.

47.73. SaveExpire

The default amount of time that a cookie will be valid (other than the MV_SESSION_ID cookie). The ones used in Interchange by default are MV_USERNAME and MV_PASSWORD for the CookieLogin feature. Specified the same as SessionExpire, with an integer number followed by one of minutes, hours, days, or weeks.

   SaveExpire 52 weeks

Default is 30 days.

47.74. ScratchDefault

The default scratch variable settings that the user will start with when their session is initialized.

To disable placing URL rewrite strings after the user has given a cookie, set:

   ScratchDefault  mv_no_session_id  1
   ScratchDefault  mv_no_count       1
   ScratchDefault  mv_add_dot_html   1

To set the default locale:

   ScratchDefault  mv_locale         de_DE

47.75. ScratchDir

The directory where temporary files will be written, notably cached searches and retired session IDs. Defaults to tmp in the catalog directory.

   ScratchDir          /tmp

47.76. SearchProfile

Allows an unlimited number of search profiles to be set up, specifying complex searches based on a single click. The directive accepts a file name based in the catalog directory if the path is relative:

   SearchProfile    etc/search.profiles

As an added measure of control, the specification is evaluated with the special Interchange tag syntax to provide conditional setting of search parameters. The following file specifies a dictionary-based search in the file 'dict.product':

 __NAME__ dict_search
 mv_search_file=dict.product
 mv_return_fields=1
 [if value fast_search]
   mv_dict_limit=-1
   mv_last=1
 [/if]
 __END__

The __NAME__ is the value to be specified in the mv_profile variable on the search form, as in

 <INPUT TYPE=hidden NAME=mv_profile VALUE="dict_search">

or with mp=profile in the one-click search.

 [page scan se=Renaissance/mp=dict_search]Renaissance Art</a>

Multiple profiles can reside in the same file, if separated by __END__ tokens. __NAME__ tokens should be left-aligned, and __END__ must be on a line by itself with no leading or trailing whitespace.

47.77. SecureURL

The base URL for secure forms/page transmissions. Normally it is the same as VendURL except for the https: protocol definition. Default is blank, disabling secure access.

   SecureURL   https://machine.com/xyzcorp/cgi-bin/vlink

47.78. SendMailProgram

The location of the sendmail binary, needed for mailing orders. Must be found at startup. This often needs to be set for FreeBSD or BSDI.

  SendMailProgram    /usr/sbin/sendmail

If set to none, no mail can be sent by standard Interchange facilities. The default is the value in interchange.cfg and varies depending on operating system.

47.79. SeparateItems

Changes the default when ordering an item via Interchange to allowing multiple lines on the order form for each item. The default, No, puts all orders with the same part number on the same line.

Setting SeparateItems to Yes allows the item attributes to be easily set for different instances of the same part number, allowing easy setting of things such as size or color.

   SeparateItems       Yes

Can be overridden with the mv_separate_items variables (both scratch and values).

47.80. SessionDatabase

When storing sessions, specify the name of the directory or DBM file to use. The file extensions of .db or .gdbm (depending on the DBM implementation used) will be appended. If the default file-based sessions are used, it is the name of the directory.

   SessionDatabase     session-data

Can be an absolute path name, if desired.

It is possible for multiple catalogs to share the same session file, as well as for multiple Interchange servers to serve the same catalogs. If serving a extremely busy store, multiple parallel Interchange servers can share the same NFS-based file system and serve users in a "ping-pong" fashion using the file-based sessions. On huge systems, the level of directory hashing may be changed. By default, only 48 * 48 hashing is done. See the source for SessionFile.pm.

47.81. SessionDB

The name of the Interchange database to be used for sessions if DBI is specified as the session type. This is not recommended.

47.82. SessionExpire

A customer can exit the browser or leave the catalog pages at any time, and no indication is given to the web server aside from the lack of further requests that have the same session ID. Old session information needs to be periodically expired. The SessionExpire specifies the minimum time to keep track of session information. Defaults to one day. Format is an integer number, followed by s(econds), m(inutes), h(ours), d(ays), or w(eeks).

   SessionExpire       20 minutes

If CookieLogin is in use, this can be a small value. If the customer's browser has the Interchange session cookie stored, he/she will be automatically logged back in with the next request. Note, however, that the customer's cart and session values will be reset.

47.83. SessionLockFile

The file to use for locking coordination of the sessions.

   SessionLockFile     session-data.lock

This only applies when using DBM-based sessions. It is possible for multiple catalogs to share the same session file. SessionDatabase needs to be set appropriately if the database is to be shared. Defaults to session.lock, which is appropriate for separate session files (and therefore standalone catalogs). Can be an absolute path name, if desired.

47.84. SessionType

The type of session management to be used. Use one of the following:

   DB_File     Berkeley DB
   DBI         DBI (don't use this, normally)
   File        File-based sessions (the default)
   NFS         File-based sessions, forces use of fcntl locking
   GDBM        GDBM

The default is file-based sessions, which provides the best performance and reliability in most environments.

If you are planning on running Interchange servers with an NFS-mounted filesystem as the session target, you must set SessionType to "NFS". The other requisites are usually:

1. fcntl() supported in Perl 2. lock daemon running on NFS server system 3. lock daemon running on Interchange server

See also the global directive LockType.

47.85. SpecialPage

Sets a special page to other than its default value. Can be set as many times as necessary. Will have no effect if not one of the Interchange Required Pages.

   SpecialPage         checkout ord/checkout
   SpecialPage         failed special/error_on_order
   SpecialPage         interact special/browser_problem
   SpecialPage         noproduct special/no_product_found
   SpecialPage         order  ord/basket
   SpecialPage         search srch/results

47.86. SpecialPageDir

The directory where special pages are kept. Defaults to special_pages in the catalog directory.

   SpecialPageDir      pages/special

47.87. Static

A Yes/No directive. Enables static page building and display features. Default is No.

    Static   Yes

47.88. StaticAll

A Yes/No directive. Tells Interchange to try and build all pages in the catalog statically when called with the static page build option. This is subject to the settings of StaticFly, StaticPath, and NoCache. Default is No. Pages that have dynamic elements will not be built statically, though that may be overridden with [tag flag build][/tag] on the page in question.

    StaticAll   Yes

47.89. StaticDepth

The number of levels of static search building that will be done if a search results page contains a search. Default is one, though it could be very long if set higher. Set to 0 to disable re-scanning of search results pages.

    StaticDepth 2

47.90. StaticDir

The absolute path of the directory which should be used as the root for static pages. The user ID executing Interchange must have write permission on the directory (and all files within) if this is to work.

    StaticDir   /home/you/www/catalog

47.91. StaticFly

A Yes/No directive. If set to Yes, static builds will attempt to generate a page for every part number in the database using the on-the-fly page build capability. If pages are already present with those names, they will be overwritten. The default is No.

    StaticFly   Yes

47.92. StaticPage

Tells Interchange to build the named page (or pages, whitespace separated) when employing the static page-building capability of Interchange. Not necessary if using StaticAll.

    StaticPage   info/about_us  info/terms_and_conditions

47.93. StaticPath

The path (relative to HTTP document root) which should be used in pages built with the static page-building capability of Interchange.

    StaticPath    /catalog

47.94. StaticPattern

A perl regular expression which is used to qualify pages that are to be built statically. The default is blank, which means all pages qualify.

    StaticPattern  ^info|^help

47.95. StaticSuffix

The extension to be appended to a normal Interchange page name when building statically. Default is .html. Also affects the name of pages in the Interchange page directory. If set to .htm, the pages must be named with that extension.

    StaticSuffix   .htm

47.96. Sub

Defines a catalog subroutine for use by the [perl][/perl] or [mvasp] embedded perl languages. Use the "here document" capability of Interchange configuration files to make it easy to define:

   Sub <<EOF
   sub sort_cart_by_quantity {
       my($items) = @_;
       $items = $Items if ! $items;
       my $out = '<TABLE BORDER=1>';
       @$items = sort { $a->{quantity} <=> $b->{quantity} } @$items;
       foreach $item (@$items) {
           my $code = $item->{code};
           $out .= '<TR><TD>';
           $out .= $code;
           $out .= '</TD><TD>';
           $out .= $Tag->data('products', 'name', $code);
           $out .= '</TD><TD>';
           $out .= $Tag->data('products', 'price', $code);
           $out .= '</TD></TR>';
       }
       $out .= '&lt/TABLE>';
       return $out;
   }
   EOF

As with Perl "here documents," the EOF (or other end marker) must be the ONLY thing on the line, with no leading or trailing white space. Do not append a semicolon to the marker. The above would be called with:

   [perl]
       my $cart = $Carts->{main};
       return sort_cart_by_quantity($cart);
   [/perl]

and will display an HTML table of the items in the current shopping cart, sorted by the quantity. Syntax errors will be reported at catalog startup time.

Catalog subroutines may not perform unsafe operations. The Safe.pm module enforces this unless global operations are allowed for the catalog. See AllowGlobal.

47.97. Suggests

Generates a warning message when a Perl module, global UserTag, or GlobalSub is not present at catalog configuration time. Same as the Require directive except not fatal.

   Suggest usertag   table_editor
   Suggest globalsub file_info
   Suggest module    Business::UPS

47.98. TableRestrict

Used to provide "views" in database-based searches. Does not affect the text searches. Affects the table being searched.

Takes the form of field=session_param, where field is a column in the table being iterated over, and session_param is a $Session key (i.e., [data session username]).

   TableRestrict  products  owner=username

The above would prevent the database search from returning any records except those where the column owner contains the current value of [data session username].

Probably most usefully set by embedded Perl code in certain situations. For example:

   [calc]
       # Restrict edit to owned fields
       $Config->{TableRestrict}{products} = 'owner=username';
       return;
   [/calc]

When using SQL-based databases, in effect it turns the base search query

   select * from products

into

   select * from products where owner = '[data session username]'

Interchange databases are similarly affected, though the methodology is different. Also may be useful in "mall" situations, where user is allowed to only see products from the current store ID.

47.99. TaxShipping

A comma or space-separated list of states or jurisdictions that tax shipping cost, i.e., UT. Blank by default, never taxing shipping.

   TaxShipping         UT,NV,94024

47.100. TemplateDir

Sets one or more directories (separated by whitespace) which will be searched (in order) for pages not found in the PageDir. If a page is not found in directories specified here, the search continues with the global TemplateDir setting, if defined.

   TemplateDir    /var/lib/interchange/foundation/bonus_pages

This is undefined by default.

47.101. TrackFile

Name of a logfile that tracks user traffic. This is used in the back office administration report on traffic by affiliate.

The default is that no such file is kept.

See Usertracking for more information.

47.102. UpsZoneFile

The file containing the UPS zone information, specified relative to the catalog directory unless it begins with a /. It can be in the format distributed by UPS or can be in a tab-delimited format, with the three-letter zip prefix of the customer used to determine the zone. It interpolates based on the value in mv_shipmode. A user database named the same as the mv_shipmode variable must be present or the lookup will return zero.

IMPORTANT NOTE: Zone information and updated pricing from UPS must be obtained in order for this to work properly. The zone information is specific to a region!

   UpsZoneFile         /usr/interchange/data/ups_zone.asc

47.103. UseModifier

Determines whether any attributes, the modifiers specified in the directive, can be attached to the item. See Item Attributes. The default is no modifier. Don't use a value of quantity or this directive will not work properly.

   UseModifier         size,color

Some values are used by Interchange and are not legal:

       mv_mi
       mv_si
       mv_ib
       group
       code
       quantity
       item

47.104. UserDB

Sets parameters to define the behavior of Interchange's user database functions.

Parameter Default Explanation
acl acl Set field for simple access control storage
addr_field address_book Set field name for address book
assign_username 0 Tell interchange to automatically assign username
bill_field accounts Set field name for accounts
cart_field carts Set field name for cart storage
clear_coookie   Comma-separated list of cookies to clear on explicit logout
clear_session   Clear user session completely on logout
counter   Counter file for assign_username function
crypt 1 Encrypt (1) or not encrypt (0) passwords
database userdb Sets user database table
db_acl db_acl Set field for database access control storage
expire_field expiration Set field for expiration date
file_acl file_acl Set field for file access control storage
force_lower 0 Force possibly upper-case database fields to lower case session variable names
ignore_case 0 Ignore case in usernames/passwords
indirect_login   Log in field if different than real username
logfile error.log File to log authentications/errors
md5 0 Use MD5 for encryption algorithm instead of crypt
no_get 0 Don't get values from database on login
no_login 0 Log people in to accounts even if they are already logged in
outboard_key_col   Set field providing key for outboard tables
outboard   Set fields that live in another table
pass_field password Set field name for password
passminlen 2 Minimum length for password
pref_field preferences Set field name for preferences
scratch   Fields to set in user Scratch space (instead of Values)
sql_counter   SQL counter spec (sequence or AUTO_INCREMENT) for assign_username function
super_field super Field to determine superuser status if admin profile
time_field time Set field for storing last login time
unix_time 0 Set if unix (seconds since 1970) time to go in log files
userminlen 2 Minimum length for username
username_mask   Regular expression usernames must not match

These are set in a catalog.cfg file with something like:

UserDB default crypt 0 UserDB admin crypt 1 UserDB admin md5 1

where default or admin is the name of the profile to set. These can be overriden if passed in the tag:

   [userdb userminlen=6 new-account=1]

47.105. UserTag

Defines a catalog-based UserTag that will run under Safe.pm restrictions. For many purposes, a global UserTag (CfgUserTagGlobal) is better.

47.106. ValuesDefault

Sets the initial state of the user values, i.e., [value key] or $Values->{key}.

   ValuesDefault   fname  New
   ValuesDefault   lname  User

When the user session starts, [value fname] [value lname] will be "New User."

47.107. Variable

Defines a catalog variable that will be available in the current catalog with the notation __VARIABLE__. Variable identifiers must begin with a capital letter, and can contain only word characters (A-Z,a-z,0-9 and underscore). They are case-sensitive.

   Variable   DOCUMENT_ROOT   /usr/local/etc/httpd/htdocs

Only variables with ALL CAPS names will be parsed in catalog pages or, when the ParseVariables directive is set, in catalog configuration directives (other than in Variable directives themselves). These are substituted second (right after global Variables) in any Interchange page, and can contain any valid Interchange tags except global variables. If a variable is called with the notation @_VARIABLE_@, and there is no catalog Variable with its name, the global Variable value will be inserted.

47.108. VariableDatabase

The name of a database containing a field Variable which will be used to set Interchange variable values. For example, a database defined as:

   Database  var var.txt TAB
   VariableDatabase var

and containing

   code    Variable
   HELLO   Hi!

would cause __HELLO__ to appear as Hi!.

The field name is case-sensitive, and variable would not work.

The values are inserted at time of definition. Any single-level hash-oriented Interchange directive, such as SpecialPage, ScratchDefault, or ValuesDefault, can be set in the same way. If the VariableDatabase named does not exist at definition time, a database of the default type with an ASCII file source appending .txt is assumed. In other words:

   VariableDatabase variable

is equivalent to

   Database         variable variable.txt TAB
   VariableDatabase variable

47.109. VendURL

Specifies the base URL that will run vlink as a cgi-bin program.

       VendURL  http://machine.company.com/cgi-bin/vlink

47.110. WideOpen

Disables IP qualification of user sessions. This degrades catalog security. Do not use unless using encryption or a real-time payment gateway.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Content Editor Reference

48. Interchange UI -- Content Editor

Interchange is a web presentation framework which has powerful database and content manipulation features. The Interchange Content Editor provides a framework for manipulating pages and components within pages.

48.1. Content management concept

Interchange assumes that the page is the basic level of content. Each page is typically a file on the filesystem, though it is possible to maintain them in a database instead.

Each page is assumed to be based on a template, which is the layout for that page. Each template can contain slots for components.

Components are interchangeable items that can be inserted in template slots so that pages based on a common template can vary without having to create a separate template.

A page may actually be a metacontent template in effect. Examples of this are the flypage for building a product page, and the results page that displays search lists.

48.2. A typical page

Here is how the file for a page looks:

        [comment]
        ui_name: typical.html
        ui_page_template: leftonly
        [/comment]

        [set page_title] A typical page [/set]
        [set members_only]0[/set]

        [control reset=1]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control reset=1]

        @_LEFTONLY_TOP__@

        <!-- BEGIN CONTENT -->

                The content of a typical page.

        <!-- END CONTENT -->

        @_LEFTONLY_BOTTOM__@

You can see other examples in the standard Interchange foundation demo.

We will tour the page, adding the PREAMBLE and POSTAMBLE sections.

Editor information

The comment at the top of the page is only used by the editor to derive things it may need to know. If it were to be removed, the page would display the same; it just may not read and publish the same when edited.

        [comment]
        ui_template_name: leftonly
        ui_static: 0
        [/comment]

In the case above, the template is specified with ui_template_name and the page will not be published statically (i.e. ui_static: 0).

PREAMBLE

The PREAMBLE is a section which allows page initialization prior to the header portion of the template, and prior to the setting of the page controls.

        <!-- BEGIN PREAMBLE -->
                [perl]
                        &custom_init();
                [/perl]
        <!-- END PREAMBLE -->

Page controls

Page controls are specified in the template definition, and the user can set them from the page control menu when editing the page.

        [set page_title] A typical page [/set]
        [set members_only]0[/set]

The above sets two page controls, one used in the header to set the HTML title for the page, and the other used to determine if the customer must be logged in (a member) to access the page.

Component controls

As was said before, a page template can contain multiple components. Each component can have an unlimited number of settings which can be used to specify its behavior. These settings are manipulated in the component control sections of the content editor, one for each component slot.

        [control reset=1]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control reset=1]

Template header section

This is the Variable used to contain the top portion of the template, which may use various page control settings and have multiple slots for components.

        @_LEFTONLY_TOP__@

CONTENT section

This is the actual content of the page. It can be edited in a TEXTAREA in the content editor.

        <!-- BEGIN CONTENT -->

                The content of a typical page.

        <!-- END CONTENT -->

Template footer section

This is the Variable used to contain the bottom portion of the template, which may use various page control settings and have multiple slots for components.

        @_LEFTONLY_BOTTOM__@

POSTAMBLE

The POSTAMBLE section can contain cleanup code for the page. It will rarely be used.

        <!-- BEGIN POSTAMBLE -->
                [perl]
                        &custom_cleanup();
                [/perl]
        <!-- END POSTAMBLE -->

Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Interchange Databases

49. Databases and Interchange

Interchange is database-independent, perhaps more so than almost any other powerful content management system.

Interchange can use GDBM, DB_File, SQL, LDAP, or in-memory databases. In most cases, these different database formats should operate the same when called by Interchange's access methods.

Also, most all of Interchange's core functions do not use hard-coded field names; virtually every field can have a configurable name.

Interchange does not require an external SQL database. If you have a small data set and do not want to integrate your own tool set, you cound use Interchange's internal database. However, the order management functions of Interchange will be slower and not as robust without an SQL database. SQL is strongly recommended for at least the state, country, orderline, transactions, and userdb tables. Any other tables that will have programmatic updates, such as inventory, will be best placed in SQL.

If you plan on using Interchange Admin UI, you should make the move to SQL. It provides easy import routines for text files that should replace text-file uploads.

Keeping a database in an SQL manager makes it easier to integrate Interchange with other tools. Interchange can be used to maintain a spreadsheet containing product information through modifying the file products.txt as needed. References to SQL, DBI, and DBD can be ignored.

49.1. Text Source Files

Interchange reads delimited text files to obtain its initial data. However, the text files are not the database. They are the source information for the database tables.

By default, all database source files are located in the products subdirectory of the catalog directory. The main products database is in the products/products.txt file in the supplied demo catalog.


Note: If you are using one of the internal database methods, any changes made to the ASCII source file will be reflected in the database in the next user session. If the product database contains less than a thousand records, updates will be instantaneous. If the product database is larger, updates will take longer. Use the NoImport reference tag to stop auto updating.

In the following configuration directive:

   Database  products  products.txt   TAB

the products table will obtain its source information from the file products.txt. What is done with it depends on the type of underlying database being used. The different types and their behavior are described below:

GDBM

            NoImport  products
            Database products IMPORT_ONCE 1

DB_File

           Database  products  DB_FILE   1

DBI/SQL

In-Memory

           Database   products   MEMORY   1

49.2. Interchange Database Conventions

This section describes naming and file usage conventions used with Interchange.


Note: Throughout the documentation, the following terms and their definitions are used interchangeably:

key, code

field, column

table, database

If necessary, Interchange can read the data to be placed in tables from a standard ASCII-delimited file. All of the ASCII source files are kept in the products directory, which is normally in the catalog directory (where catalog.cfg is located). The ASCII files can have ^M (carriage return) characters, but must have a new line character at the end of the line to work. NOTE: Mac users uploading files must use ASCII mode, not binary mode.

Interchange's default ASCII delimiter is TAB.


Note: The items must be separated by a single delimiter. The items in this document are lined up for reading convenience.

TAB

            code    description             price   image
            SH543   Men's fine cotton shirt 14.95   shirts.jpg

PIPE

            code|description|price|image
            SH543|Men's fine cotton shirt|14.95|shirts.jpg

CSV

            "code","description","price","image"
            "SH543","Men's fine cotton shirt","14.95","shirts.jpg"


Note: Using the default TAB delimiter is recommended if you plan on searching the ASCII source file of the database. PIPE works fairly well, but CSV delimiter schemes might cause problems with searching.


IMPORTANT NOTE: Field names are usually case-sensitive. Use consistency when naming or you might encounter problems. All lower or all upper case names are recommended.

49.3. The Product Database

Each product being sold should be given a product code, usually referred to as SKU, a short code that identifies the product on the ordering page and in the catalog. The products.txt file is a ASCII-delimited list of all the product codes, along with an arbitrary number of fields which must contain at least the fields description and price (or however the PriceField and DescriptionField directives have been set). Any additional information needed in the catalog can be placed in any arbitrary field. See Interchange Database Capability for details on the format.

Field names can be case-sensitive depending on the underlying database type. Unless there are fields with the names "description" and "price" field, set the PriceField and DescriptionField directives to use the [item-price] and [item-description] tags.

The product code, or SKU, must be the first field in the line, and must be unique. Product codes can contain the characters A-Za-z0-9, along with hyphen (-), underscore (_), pound sign/hash mark (#), slash (/), and period (.). Note that slash (/) will interfere with on-the-fly page references. Avoid if at all possible.

The words should be separated by one of the approved delimiting schemes (TAB, PIPE, or CSV), and are case-sensitive in some cases. If the case of the "description" or "price" fields have been modified, the PriceField and DescriptionField directives must be appropriately set.


Note: CSV is not recommended as the scheme for the products database. It is much slower than TAB- or PIPE-delimited, and dramatically reduces search engine functionality. No field-specific searches are possible. Using CSV for any small database that will not be searched is fine.


IMPORTANT NOTE: The field names must be on the first line of the products.txt file. These field names must match exactly the field names of the [item-field] tags in the catalog pages, or the Interchange server will not access them properly. Field names can contain the characters A-Za-z0-9 and underscore (_).

More than one database may be used as a products database. If the catalog directive, ProductFiles, is set to a space-separated list of valid Interchange database identifiers, those databases will be searched (in the order specified) for any items that are ordered, or for product information (as in the [price code] and [field code] tags).

When the database table source file (i.e., products.txt) changes after import or edit, a DBM database is re-built upon the next user access. No restart of the server is necessary.

If changing the database on-the-fly, it is recommended that the file be locked while it is being modified. Interchange's supplied import routines do this.

49.4. Multiple Database Tables

Interchange can manage an unlimited number of arbitrary database tables. They use the TAB delimiter by default, but several flexible delimiter schemes are available. These are defined by default:

   Type 1      DEFAULT - uses default TAB delimiter
   Type 2      LINE
               Each field on its own line, a blank line
               separates the record. Watch those carriage
               returns! Also has a special format when CONTINUE
               is set to be NOTES.
   Type 3      %%
               Fields separated by a \n%%\n combination, records by
               \n%%%\n (where \n is a newline). Watch those carriage
               returns!
   Type 4      CSV
   Type 5      PIPE
   Type 6      TAB
   Type 7      reserved
   Type 8      SQL
   Type 9      LDAP

The databases are specified in Database directives, as:

   Database    arbitrary arbitrary.csv CSV

This specifies a Type 4 database, the ASCII version of which is located in the file arbitrary.csv, and the identifier it will be accessed under in Interchange is "arbitrary." The DBM file, if any, will be created in the same directory if the ASCII file is newer, or if the DBM file does not exist. The files will be created as arbitrary.db or arbitrary.gdbm, depending on DBM type.

The identifier is case sensitive, and can only contain characters in the class [A-Za-z0-9_]. Fields are accessed with the [item_data identifier field] or [data identifier field key] elements. NOTE: Use of lower-case letters is strongly recommended.

If one of the first six types is specified, the database will automatically be built in the default Interchange DB style. The type can be specified with DB_FILE, GDBM, or MEMORY, if the type varies from that default. They will coexist with an unlimited number of DBI databases of different types.

In addition to the database, the session files will be kept in the default format, and are affected by the following actions.

The order of preference is:

GDBM

            perl -e 'require GDBM_File and print "I have GDBM.\n"'

DB_File (Berkeley DB)

            perl -e 'require DB_File and print "I have Berkeley DB.\n"'
            # csh or tcsh
            setenv MINIVEND_DBFILE 1
        
            # sh, bash, or ksh
            MINIVEND_DBFILE=1 ; export MINIVEND_DBFILE
            Database arbitrary  DB_FILE  1

In-memory

            Database arbitrary  MEMORY  1


Note: The use of memory databases is not recommended.

49.5. Character Usage Restrictions

To review, database identifiers, field names, and product codes (database keys) are restricted in the characters they may use. The following table shows the restrictions:

                                  Legal characters
                                  ---------------------
 Database identifiers             A-Z a-z 0-9 _
 Field names                      A-Z a-z 0-9 _
 Database keys (product code/SKU) A-Z a-z 0-9 _ # - . /
 Database values                  Any (subject to field/record delimiter)

Some SQL databases have reserved words which cannot be used as field names; Interchange databases do not have this restriction.

For easy HTML compatibility, it is not recommended that a / be used in a part number if using the flypage capability. It can still be called [page href=flypage arg="S/KU"].

49.6. Database Attributes

Especially in SQL databases, there are certain functions that can be set with additional database attributes. For text import, the CONTINUE extended database import attribute allows additional control over the format of imported text.


Note: CONTINUE applies to all types except CSV. (Do not use NOTES unless using type LINE.)

CONTINUE

          Database products products.txt  TAB
          Database products CONTINUE      DITTO
          code     price     description
          00-0011  500000    The Mona Lisa, one of the worlds great masterpieces.
                             Now at a reduced price!


Note: Fields are separated by tabs, formatted for reading convenience.

          Database products products.txt  LINE
          Database products CONTINUE      LINE
            code
            price
            description
        
            00-0011
            500000
            The Mona Lisa, one of the worlds great masterpieces.
            Now at a reduced price!
        
            00-0011a
            1000
            A special frame for the Mona Lisa.
          Database products products.txt  LINE
          Database products CONTINUE      NOTES
            code
            title
            price
            image
            description ~
            size
            color
        
            title: Mona Lisa
            price: 500000
            code: 00-0011
            image: 00-0011.jpg
        
            The Mona Lisa, one of the worlds great masterpieces.
            Now at a reduced price!
            ~
            title: The Art Store T-Shirt
            code: 99-102
            size: Medium, Large*, XL=Extra Large
            color: Green, Blue, Red, White*, Black
            price: 2000
        
            Extra large 1.00 extra.
            ~

EXCEL

            Database products EXCEL 1

LARGE

        Database transactions LARGE 1

49.7. Dictionary Indexing With INDEX

Interchange will automatically build index files for a fast binary search of an individual field. This type of search is useful for looking up the author of a book based on the beginning of their last name, a book title based on its beginning, or other similar situations.

Such a search requires a dictionary ordered index with the field to be searched contained in the first field and the database key (product code) in the second field. If the INDEX field modifier is specified, Interchange will build the index upon database import:

  Database  products  products.txt   TAB
  Database  products  INDEX          title

If the title field is the fourth column in the products database table, a file products.txt.4 will be built, containing two tab-separated fields something like:

   American Gothic   19-202
   Mona Lisa         00-0011
   Sunflowers        00-342
   The Starry Night  00-343

Options can be appended to the field name after a colon (:). The most useful will be f, which does a case-insensitive sort. The mv_dict_fold option must be added to the search in this case.

Another option is c, which stands for "comma index." To index on comma-separated sub-fields within a field, use the :c option:

  Database  products  products.txt   TAB
  Database  products  INDEX          category:c

This can get slow for larger databases and fields. Interchange will split the field on a comma (stripping surrounding whitespace) and make index entries for each one. This allows multiple categories in one field while retaining the fast category search mechanism. It might also be useful for a keywords field.

The fast binary search is described in greater detail in THE SEARCH ENGINE below.

49.8. MEMORY for Memory-Only Databases

Interchange's memory-based databases are the fastest possible way to organize and store frequently used data. To force a database to be built in memory instead of DBM, use the MEMORY modifier:

  Database  country  country.asc   TAB
  Database  country  MEMORY        1

Obviously, large tables will use a great deal of memory, and the data will need to be re-imported from the ASCII source file at every catalog reconfiguration or Interchange restart. The big advantage of using MEMORY is that the database remains open at all times and does not need to be reinitialized at every connect. Use it for smaller tables that will be frequently accessed.

Memory tables are read only -- the MEMORY modifier forces IMPORT_ONCE.

49.9. IMPORT_ONCE

The IMPORT_ONCE modifier tells Interchange not to re-import the database from the ASCII file every time it changes. Normally, Interchange does a comparison of the database file modification time with the ASCII source every time it is accessed, and if the ASCII source is newer it will re-import the file.

IMPORT_ONCE tells it only to import on a server restart or catalog reconfiguration:

  Database  products  products.txt   TAB
  Database  products  IMPORT_ONCE    1

SQL databases don't normally need this. They will only be imported once in normal operation. Also see NoImport for a way to guarantee that the table will never be imported.

IMPORT_ONCE is always in effect for MEMORY databases. A catalog reconfiguration is required to force a change.

49.10. MIRROR

Additionally, you can have two tables, the regular table and the memory table by adding to the definition files:

        Database country_memory country_memory.txt TAB
        Database country_memory MIRROR          country
        Database country_memory MEMORY          1

49.11. SQL/DBI parameters

49.11.1. AUTO_SEQUENCE

Tells Interchange to use a SQL sequence to number new database items inserted into the database.

If you have Interchange create the table, then you need to do:

  Database foo foo.txt dbi:mysql:test
  Database foo AUTO_SEQUENCE foo_seq

Then on MySQL, Pg, or Oracle, Interchange will create an integer key type and a sequence (or AUTO_INCREMENT in MySQL) to maintain the count.

49.11.2. AUTO_SEQUENCE_MAXVAL

Sets the MAXVAL to have in an AUTO_SEQUENCE counter:

  Database foo AUTO_SEQUENCE_MAXVAL  1000000

49.11.3. AUTO_SEQUENCE_MINVAL

Sets the MINVAL to have in an AUTO_SEQUENCE counter:

  Database foo AUTO_SEQUENCE_MINVAL  10

49.11.4. AUTO_SEQUENCE_START

Sets the starting value for an AUTO_SEQUENCE counter:

  Database foo AUTO_SEQUENCE_START  1000

49.11.5. COMPOSITE_KEY

If you are using a DBI table with composite keys, where two or more fields combine to make the unique identifier for a record, you must tell Interchange so it can request data in the right way. To do this, set:

  Database  product_spec product_spec.asc dbi:mysql:foobase
  Database  product_spec COMPOSITE_KEY sku feature
  Database  product_spec COLUMN_DEF    "sku=varchar(32)"
  Database  product_spec COLUMN_DEF    "feature=varchar(128)"

If you want to create a custom index for the table, do so. If you don't specify a POSTCREATE or INDEX parameter for the table, Interchange will create a unique index with all composite key elements at table creation time.

49.11.6. DSN

The data source name (DSN) for the database. It is beyond the scope of this document to describe this in detail.

Normally this is set as the type in the initial Database configuration line, i.e.

  Database  foo  foo.txt  dbi:mysql:foobase

This has the same effect:

  Database  foo  foo.txt  SQL
  Database  foo  DSN      dbi:mysql:foobase

Some other examples of DSN specs:

 Database  foo  DSN  dbi:mysql:host=db.you.com;database=foobase
 Database  foo  DSN  dbi:Pg:dbname=foobase
 Database  foo  DSN  dbi:Oracle:host=myhost.com;sid=ORCL

49.11.7. HAS_TRANSACTIONS

Informs Interchange that the SQL database in use has commit() and rollback() for transactions. For PostgreSQL and Oracle this should be set properly to 1 -- for MySQL and other databases you have to set it.

49.11.8. HAS_LIMIT

Informs Interchange that the SQL database in use has as the LIMIT extension to SQL to limit return from queries. Should be set properly by default for MySQL, PostgreSQL, and Oracle.

49.11.9. POSTCREATE

One or more SQL statements that should be performed after Interchange creates a table.

 Database foo POSTCREATE "create unique index foo_idx on foo(key1,key2)"
 Database foo POSTCREATE "create index mulkey_idx on foo(mulkey)"

49.11.10. PRECREATE

One or more SQL statements that should be performed before Interchange creates a table.

 Database foo POSTCREATE "drop table foobackup"
 Database foo POSTCREATE "alter table foo rename to foobackup"

49.11.11. REAL_NAME

Sometimes it may be convenient to have a table named a consistent value in Interchange despite its name in the underlying database. For instance, two divisions of a company may share orders but have different products tables. You can tell Interchange to name the table products for its purposes, but use the products_a table for SQL statements:

 Database products REAL_NAME products_a

Of course if you have SQL queries that are passed verbatim to Interchange (i.e. the [query ...] tag) you must use the REAL_NAME in those.

49.12. Importing in a Page

To add a data record to a database as a result of an order or other operation, use Interchange's [import ...] tag.

[import table type*] RECORD [/import]

         [import table=table_name
                 file=filename*
                 type=(TAB|PIPE|CSV|%%|LINE)*
                 continue=(NOTES|UNIX|DITTO)*
                 separator=c*]

Import one or more records into a database. The type is any of the valid Interchange delimiter types, with the default being TAB. The table must already be a defined Interchange database table. It cannot be created on-the-fly. If on-the-fly functionality is need, it is time to use SQL.

The import type selected need not match the type the database was specified. Different delimiters may be used.

The type of LINE and continue setting of NOTES is particularly useful, for it allows fields to be named and not have to be in any particular order of appearance in the database. The following two imports are identical in effect:

   [import table=orders]
            code: [value mv_order_number]
   shipping_mode: [shipping-description]
          status: pending
   [/import]

   [import table=orders]
   shipping_mode: [shipping-description]
   status:        pending
   code:          [value mv_order_number]
   [/import]

The code or key must always be present, and is always named code. If NOTES mode is not used, the fields must be imported in the same order as they appear in the ASCII source file.

The file option overrides the container text and imports directly from a named file based in the catalog directory. To import from products.txt, specify file="products/products.txt". If the NoAbsolute directive is set to Yes in interchange.cfg, only relative path names will be allowed.

The [import ....] TEXT [/import] region may contain multiple records. If using NOTES mode, a separator must be used, which, by default, is a form-feed character (^L). See Import Attributes for more information.

49.13. Exporting from a Database

To export an existing database to a file to its text file, suitable for full-text search by Interchange, use Interchange's UI create a page that contains a [export table=TABLENAME] ITL tag (ExportTag).

49.14. Write Control

Interchange databases can be written in the normal course of events, either using the [import ...] tag or with a tag like [data table=table column=field key=code value=new-value]. To control writing of a global database, or to a certain catalog within a series of subcatalogs, or make one read only, see the following:

To enable write control:

   Database   products  WRITE_CONTROL  1

Once this is done, to make a database read only, which won't allow writing even if [tag flag write]products[/tag] is specified:

   Database   products  READ_ONLY  1

To have control with [tag flag write]products[/tag]:

   Database   products  WRITE_TAGGED  1

To limit write to certain catalogs, set:

   Database   products  WRITE_CATALOG  simple=0, sample=1

The "simple" catalog will not be able to write, while "sample" will if [tag flag write]products[/tag] is enabled. If a database is to always be writable, without having to specify [tag flag write] ... [/tag], then define:

   Database   products  WRITE_ALWAYS  1

The default behavior of SQL databases is equivalent to WRITE_ALWAYS, while the default for GDBM_File, DB_File, and Memory databases is equivalent to:

   Database   products  WRITE_CONTROL 1
   Database   products  WRITE_TAGGED  1

49.15. Global Databases

If a database is to be available to all catalogs on the Interchange server, it may be defined in interchange.cfg. Any catalog running under that server will be able to use it. It is writable by any catalog unless WRITE_CONTROL is used.

50. SQL Support

Interchange can use any of a number of SQL databases through the powerful Perl DBI/DBD access methods. This allows transparent access to any database engine that is supported by a DBD module. The current list includes mSQL, MySQL, Solid, PostgreSQL, Oracle, Sybase, Informix, Ingres, Dbase, DB2, Fulcrum, and others. Any ODBC (with appropriate driver) should also be supported.

No SQL database is included with Interchange, but there are a number widely available on the Internet. Most commonly used with Interchange are PostgreSQL, MySQL, and Oracle. It is beyond the scope of this document to describe SQL or DBI/DBD. Sufficient familiarity is assumed.

In most cases, Interchange cannot perform administrative functions, like creating a database or setting access permissions. This must be done with the tools provided with a SQL distribution. But, if given a blank database and the permission to read and write it, Interchange can import ASCII files and bootstrap from there.

50.1. SQL Support via DBI

The configuration of the DBI database is accomplished by setting attributes in additional Database directives after the initial defining line as described above. For example, the following defines the database arbitrary as a DBI database, sets the data source (DSN) to an appropriate value for an mSQL database named minivend on port 1114 of the local machine:

   Database arbitrary arbitrary.asc SQL
   Database arbitrary DSN           dbi:mSQL:minivend:localhost:1114

As a shorthand method, include the DSN as the type:

   Database arbitrary arbitrary.asc dbi:mSQL:minivend:localhost:1114

Supported configuration attributes include (but are not limited to):

DSN

            dbi:mSQL:minivend:othermachine.my.com:1112

USER

PASS

COLUMN_DEF

NAME

NUMERIC

UPPERCASE

DELIMITER

KEY

ChopBlanks, LongReadLen, LongTruncOK, RaiseError, etc.

          ChopBlanks
          CompatMode
          LongReadLen
          LongTruncOk
          PrintError
          RaiseError
          Warn

Here is an example of a completely set up DBI database on MySQL, using a comma-separated value input, setting the DBI attribute LongReadLen to retrieve an entire field, and changing some field definitions from the default char(128):

 Database   products  products.csv  dbi:mysql:minivend
 Database   products  USER          minivend
 Database   products  PASS          nevairbe
 Database   products  DELIMITER     CSV

 # Set a DBI attribute
 Database   products  LongReadLen   128

 # change some fields from the default field type of char(128)
 # Only applies if Interchange is importing from ASCII file
 # If you set a field to a numeric type, you must set the
 # NUMERIC attribute
 Database   products  COLUMN_DEF    "code=char(20) NOT NULL primary key"
 Database   products  COLUMN_DEF    price=float, discount=float
 Database   products  COLUMN_DEF    author=char(40), title=char(64)
 Database   products  COLUMN_DEF    nontaxable=char(3)
 Database   products  NUMERIC       price
 Database   products  NUMERIC       discount

MySQL, DBI, and DBD::mysql must be completely installed and tested, and have created the database minivend, for this to work. Permissions are difficult on MySQL. if having trouble, try starting the MySQL daemon with safe_mysqld --skip-grant-tables & for testing purposes.

To change to ODBC, the only changes required might be:

   Database products  DSN         dbi:ODBC:TCP/IP localhost 1313
   Database products  ChopBlanks  1

The DSN setting is specific to a ODBC setup. The ChopBlanks setting takes care of the space-padding in Solid and some other databases. It is not specific to ODBC. Once again, DBI, DBD::ODBC, and the appropriate ODBC driver must be installed and tested.

50.2. SQL Access Methods

An Interchange SQL database can be accessed with the same tags as any of the other databases can. Arbitrary SQL queries can be passed with the [query sql="SQL STATEMENT"] ITL tag.

    [query
        ml=10
        more=1
        type=list
        sp="@@MV_PAGE@@"
        sql=|
            SELECT  sku, description
            FROM    products
            WHERE   somecol
                                        BETWEEN '[filter sql][cgi from][/filter]'
                                        AND '[filter sql][cgi to][/filter]'
            AND     someothercol = '[filter sql][cgi whatever][/filter]'
            ORDER BY sku
        |]
        [list]
            sku=[sql-code] - desc=[sql-param description]<br>
        [/list]
        [on-match]
            Something was found<br>
        [/on-match]
        [no-match]
            Nothing was found<br>
        [/no-match]
        [more-list]
                <br>[matches]<br>
        [/more-list]
    [/query]

Not the filter for [cgi foo] values, which prevent single quotes (') from destroying the query.

50.3. Importing from an ASCII File

When importing a file for SQL, Interchange by default uses the first column of the ASCII file as the primary key, with a char(16) type, and assigns all other columns a char (128) definition. These definitions can be changed by placing the proper definitions in COLUMN_DEF Database directive attribute:

 Database  products  COLUMN_DEF  price=char(20), nontaxable=char(3)

This can be set as many times as desired, if it will not fit on the line.

 Database  products  COLUMN_DEF  price=char(20), nontaxable=char(3)
 Database  products  COLUMN_DEF  description=char(254)

To create an index automatically, append the information when the value is in quotes:

 Database  products  COLUMN_DEF  "code=char(14) primary key"

The field delimiter to use is TAB by default, but can be changed with the Database DELIMITER directive:

 Database  products products.csv dbi:mSQL:minivend:localhost:1114
 Database  products DELIMITER  CSV

To create other secondary keys to speed sorts and searches, do so in the COLUMN_DEF:

 Database  products COLUMN_DEF  "author=char(64) secondary key"

Or use external database tools. NOTE: Not all SQL databases use the same index commands.

To use an existing SQL database instead of importing, set the NoImport directive in catalog.cfg to include any database identifiers not to be imported:

   NoImport  products inventory


WARNING: If Interchange has write permission on the products database, be careful to set the NoImport directive or create the proper .sql file. If that is not done, and the database source file is changed, the SQL database could be overwritten. In any case, always back up the database before enabling it for use by Interchange.

51. Managing DBM Databases

51.1. Making the Database

The DBM databases can be built offline with the offline command. The directory to be used for output is specified either on the command line with the -d option, or is taken from the catalog.cfg directive OfflineDir -- offline in the catalog directory by default. The directory must exist. The source ASCII files should be present in that directory, and the DBM files are created there. Existing files will be overwritten.

   offline -c catalog [-d offline_dir]

Do a perldoc VENDROOT/bin/offline for full documentation.

51.2. Updating Individual Records

If it takes a long time to build a very large DBM database, consider using the bin/update script to change just one field in a record, or to add from a corrections list.

The database is specified with the -n option, or is 'products' by default.

The following updates the products database price field for item 19-202 with the new value 25.00:

   update -c catalog -f price 25.00

More than one field can be updated on a single command line.

   update -c catalog -f price -f comment 25.00 "That pitchfork couple"

The following takes input from file, which must be formatted exactly like the original database, and adds/corrects any records contained therein.

   update -c catalog -i file

Invoke the command without any arguments for a usage message describing the options.

52. Other Database Capabilities

Interchange has a number of other options that can affect operation of or operations on a defined database.

52.1. Search Modification

Normally, Interchange can search any database and will return all records that match the search specification. Some attributes affect this.

52.1.1. HIDE_FIELD

When set to a field name, i.e.:

   Database  sometable  HIDE_FIELD  inactive

Interchange will not return records that have that field (in the example, c<inactive>) set to a true (non-blank, non-zero) value.

52.1.2. NO_SEARCH

An indication that the database should not be searchable by default. Used to determine the default search files for a product searc.

   Database  sometable  NO_SEARCH  1

In the foundation demo, this is used to prevent the options table from being searched for products.

52.2. Indexing

You can indicate that a database should be indexed on a field with the INDEX modifier:

        Database sometable  INDEX  category

This will create an ASCII index on every import, and will also create an index on the field at SQL creation time.

If you wish to create SQL indices at table creation time without creating an ASCII index, use the NO_ASCII_INDEX parameter:

        Database sometable  NO_ASCII_INDEX  1

Of course you can create a SQL index manually at any time via your SQL toolset.

53. The Search Engine

Interchange implements a search engine which will search the product database (or any other file) for items based on customer input. It uses either forms or link-based searches that are called with the special page name scan. The search engine uses many special Interchange tags and variables.

If the search is implemented in a link or a form, it will always display formatted results on the results page, an Interchange page that uses some combination of the [search-region], [search-list], [more-list], [more], and other Interchange tags to format and display the results. The search results are usually a series of product codes/SKUs or other database keys, which are then iterated over similar to the [item-list].


Note: Examples of search forms and result pages are included in the demos.

Two search engine interfaces are provided, and five types of searching are available. The default is a text-based search of the first products database source file (i.e., products.txt). A binary search of a dictionary-ordered file can be specified. An optional Glimpse search is enabled by placing the command specification for Glimpse in the catalog.cfg directive Glimpse. There is a range-based search, used in combination with one of the above. And finally, there is a fully-coordinated search with grouping.

The default, a text based search, sequentially scans the lines in the target file. By default it returns the first field (delineated by the delimiter for that database) for every line matching the search specification. This corresponds to the product code, which is then used to key specific accesses to the database.

The text-based search is capable of sophisticated field-specific searches with fully-independent case-sensitivity, substring, and negated matching.

53.1. The Search Form

A number of variables can be set on search forms to determine which search will be used, what fields in the database it will search, and what search behavior will be.

Here is a simple search form:

 <FORM ACTION="[area search]" METHOD=POST>
 <INPUT TYPE="text" SIZE="30" NAME="mv_searchspec">
 <INPUT TYPE="submit" VALUE="Search">
 </FORM>

When the "Search" submit button is pressed (or <ENTER> is pressed), Interchange will search the products.txt file for the string entered into the text field mv_searchspec, and return the product code pertaining to that line.

The same search for a fixed string, say "shirt," could be performed with the use of a hot link, using the special scan URL:

 [page search="se=shirt"]See our shirt collection!</a>

The default is to search every field on the line. To match on the string "shirt" in the product database field "description," modify the search:

 <INPUT TYPE="hidden" NAME="mv_search_field" VALUE="description">

In the hot-linked URL search:

 [page search="
               se=shirt
               sf=category
           "]See our shirt collection!</a>

To let the user decide on the search parameters, use checkboxes or radiobox fields to set the fields:

   Search by author
      <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="author">
   Search by title
       <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="title">

Fields can be stacked. If more than one is checked, all checked fields will be searched.

53.2. Glimpse

To use the Glimpse search, the Glimpse index must be built based on files in the ProductDir, or wherever the files to be searched will be located. If the catalog is in /var/lib/interchange/foundation, the command line to build the index for the products file would be:

   chdir /var/lib/interchange/foundation/products
   glimpseindex -b -H . products.txt

There are several ways to improve search speed for large catalogs. One method that works well for large products.txt files is to split the products.txt file into small index files (in the example, 100 lines) with the split(1) UNIX/POSIX command. Then, index it with Glimpse:

   split -100 products.txt index.txt.
   glimpseindex -H /var/lib/interchange/foundation/products index.txt.*

This will dramatically increase search speeds for large catalogs, at least if the search term is relatively unique. If it is a common string, in a category search, for example, it is better to use the text-based search.

To search for numbers, add the -n option to the Glimpse command line.


Note: A large catalog is one of more than several thousand items; smaller ones have acceptable speed in any of the search modes.

If the Glimpse executable is not found at Interchange startup, the Glimpse search will be disabled and the regular text-based search used instead.

There are several things to watch for while using Glimpse, and a liberal dose of the Glimpse documentation is suggested. In particular, the spelling error capability will not work in combination with the field-specific search. Glimpse selects the line, but Interchange's text-based search routines disqualify it when checking to see if the search string is within one of the specified fields.

To use field-specific searching on Glimpse, tell it what the field names are. If the search is on the products database (file), nothing is needed for the default is to use the field names from the products database. If it is some other field layout, specify the file to get the field names from with mv_field_file (ff).

53.3. Fast Binary Search

Fast binary searching is useful for scanning large databases for strings that match the beginning of a line. They use the standard Perl module Search::Dict, and are enabled through use of the mv_dict_look, mv_dict_end, mv_dict_limit, mv_dict_fold, and mv_dict_order variables.

The field to search is the first field in the file, the product code should be in the second field, delimited by TAB. Set the mv_return_fields=1 to return the product code in the search.

The search must be done on a dictionary-ordered pre-built index, which can be produced with the database INDEX modifier. See Dictionary indexing with INDEX.

If using the mv_dict_look parameter by itself, and the proper index file is present, Interchange will set the options:

   mv_return_fields=1
   mv_dict_limit=-1

This will make the search behave much like the simple search described above, except it will be much faster on large files and will match only from the beginning of the field. Here is an example. A title index has been built by including in catalog.cfg:

   Database   products   INDEX    title


Note: The ASCII source file must be "touched" to rebuild the index and the database.

Now, specify in a form:

   <FORM ACTION="[process href=search]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_dict_limit VALUE=title>
   <INPUT NAME=mv_dict_look>
   </FORM>

or in a URL:

   [page search="dl=Van Gogh/di=title"]

This search is case-sensitive. To do the same thing case-insensitively:

   Database   products   INDEX    title:f

   <FORM ACTION="[process href=search]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_dict_limit VALUE=title>
   <INPUT TYPE=hidden NAME=mv_dict_fold  VALUE=1>
   <INPUT NAME=mv_dict_look>
   </FORM>

   [page search="dl=Van Gogh/di=title/df=1"]

53.4. Coordinated and Joined Searching

Interchange will do a complete range of tests on individual columns in the database. To use this function, set mv_coordinate to Yes (co=yes in the one-click syntax). In order to use coordinated searching, the number of search fields must equal the number of search strings.

To make sure that is the case, use the mv_search_map variable. It allows variables to be mapped to others in the search specification. For example:

   <INPUT TYPE=hidden NAME=mv_search_map VALUE="
       mv_searchspec=search1
       mv_searchspec=search2
       mv_searchspec=search3
       ">
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=title>
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=artist>
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
   Artist: <INPUT NAME=search1 VALUE="">
   Title:  <INPUT NAME=search2 VALUE="">
   Genre:  <INPUT NAME=search3 VALUE="">

Even if the user leaves one blank, the search will work.

Leading/trailing whitespace is stripped from all lines in the mv_search_map variable, so it can be positioned as shown for convenience.

Coordinated searches may be joined with the output of another table if set one of the mv_search_field values is set to a table:column pair. Note that this will slow down large searches considerably unless there is another search specification, as the database must be accessed for every search line If there is a search field that qualifies for a regular expression search function, or conducting a binary search with mv_dict_look, or are not doing an OR search, the penalty should not be too great as only matching lines will cause an access to the database.

Individual field operations can then be specified with the mv_column_op (or op) parameter. The operations include:

   operation            string     numeric   equivalent
   ---------
   equal to               eq         ==           =
   not equal              ne         !=           <>
   greater than           gt         >
   less than              lt         <
   less than/equal to     le         <=
   greater than/equal to  ge         >=
   regular expression     rm                       =~ , LIKE
   regular expression NOT rn                       !~
   exact match            em
   Text::Query::Advanced  aq
   Text::Query::Simple    tq

An example:

   [page search="
           co=yes
           sf=title
           se=Sunflowers
           op=em
           sf=artist
           se=Van Gogh
           op=rm
   "] Sunflowers, Van Gogh </a>

   [page search="
           co=yes

           sf=title
           se=Sunflowers
           nu=0
           op=!~

           sf=artist
           se=Van Gogh
           op=rm
           nu=0

           sf=inventory:qty
           se=1
           op=>=
           nu=1
   "] Any in stock except Sunflowers, Van Gogh </a>

Note that in the second example, nu=0 must be specified even though that is the default. This is to set the proper correspondence. To avoid having to do this, use Interchange's option array feature:

   [page search.0="
                   sf=title
                   se=Sunflowers
                   op=!~
               "
         search.1="
                   sf=artist
                   se=Van Gogh
               "
         search.2="
                   sf=inventory:qty
                   se=1
                   op=>=
                   nu=1
               "
       ] Any in stock except Sunflowers, Van Gogh </a>

The co=yes is assumed when specifying a multiple search.

The second search will check the stock status of the painting provided there is an inventory table as in some of the Interchange demo catalogs. If the qty field is greater than or equal to 1, the product will be picked. If out of stock, it will not be found.

It always helps to have an rm type included in the search. This is used to pre-screen records so that database accesses only need be made for already-matching entries. If accesses must be made for every record, large searches can get quite slow.

The special aq and tq query types only operate if the Text::Query CPAN module is installed. This allows Altavista-style searches on the field, using AND, OR, NOT, and NEAR with arbitrarily complex parentheses.

A useful form for the aq type would be:

  <form action="[area search]" method=POST>
  <input type=hidden name=mv_session_id value="[data session id]">
  <input type=hidden name=mv_column_op VALUE="aq">
  <input type=hidden name=mv_coordinate VALUE=1>
  <input type=hidden name=mv_min_string value=2>
  <input type=hidden name=mv_search_field VALUE=":sku:description:comment:category">
  <input type=hidden name=mv_searchtype VALUE=db>
  <input name=mv_searchspec type=text size=12>
  <input type=submit value="SEARCH">
  </form>

This searches the sku, description, comment, and category fields in the default products file with Text::Query syntax. Try the term "painters NEAR set" in the default foundation example.

53.5. Custom search operators

You can write your own search operator with Interchange's CodeDef. In interchange.cfg, or in the code directory tree, you can put:

 CodeDef find_mirrored SearchOp
 CodeDef find_mirrored Routine <<EOR
 sub {
       my ($self, $i, $pat) = @_;
       $pat = reverse $pat;
       return sub {
               my $string = shift;
               $string =~ /$pat/io;
       };
 }
 EOR

Now you can do:

   [loop search="
               se=sretniap
               sf=description
               fi=products
               st=db
               co=yes
               rf=*
               op=find_mirrored
           "]
   [loop-code] [loop-param description]<br>
   [/loop]

The passed parameters are:

Must return a sub which receives the data to match and returns 1 if it matches. DOES NOT HONOR mv_negate UNLESS you tell it to.

See Vend::Search::create_text_query for an example of how to return a proper routine and look in search object for the associated params.

53.6. Specifying a Text-Based Search with SQL Syntax

If the Perl SQL::Statement module is installed, SQL syntax can be specified for the text-based search. This is not the same as the external SQL database search, treated below separately. This works on the ASCII text source file, not on the actual database.

This syntax allows this form setup:

   Artist: <INPUT NAME="artist">
   Title:  <INPUT NAME="title">
   <INPUT TYPE=hidden NAME="mv_sql_query"
           VALUE="
               SELECT code FROM products
               WHERE artist LIKE artist
               AND    title LIKE title">

If the right hand side of an expression looks like a column, i.e., is not quoted, the appropriate form variable is substituted. (If used in a one-click, the corresponding scratch variable is used instead.) The assumption is reversed for the left-hand side. If it is a quoted string, the column name is read from the passed values. Otherwise, the column name is literal.

   Search for: <INPUT NAME="searchstring"><BR>
   Search in   <INPUT TYPE="radio" NAME="column" VALUE="title"> title
       <INPUT TYPE="radio" NAME="column" VALUE="artist"> artist
       <INPUT TYPE=hidden NAME="mv_sql_query"
         VALUE="SELECT code FROM products WHERE 'column' LIKE searchstring">

Once again, this does not conduct a search on an SQL database, but formats a corresponding text-based search. Parentheses will have no effect, and an OR condition will cause all conditions to be OR. The searches above would be similar to:

   [page search="
               co=yes
               sf=artist
               op=rm
               se=[value artist]
               sf=title
               op=rm
               se=[value title]
           "  ]
       Search for [value artist], [value title]
   </a>

   [page search="
               co=yes
               sf=[value column]
               op=rm
               se=[value searchstring]
           "  ]
   Search for [value searchstring]
          in  [value column]
   </a>

53.7. One-Click Searches

Interchange allows a search to be passed in a URL, as shown above. Just specify the search with the special page parameter search or special page scan. Here is an example:

    [page search="
               se=Impressionists
               sf=category
           "]
       Impressionist Paintings
    </a>

This is the same:

    [page scan se=Impressionists/sf=category]
       Impressionist Paintings
    </a>

Here is the same thing from a home page (assuming /cgi-bin/vlink is the CGI path for Interchange's vlink):

    <A HREF="/cgi-bin/vlink/scan/se=Impressionists/sf=category">
       Impressionist Paintings
    </A>

The two-letter abbreviations are mapped with these letters:

 ac  mv_all_chars
 bd  mv_base_directory
 bs  mv_begin_string
 ck  mv_cache_key
 co  mv_coordinate
 cs  mv_case
 cv  mv_verbatim_columns
 de  mv_dict_end
 df  mv_dict_fold
 di  mv_dict_limit
 dl  mv_dict_look
 DL  mv_raw_dict_look
 do  mv_dict_order
 dr  mv_record_delim
 em  mv_exact_match
 er  mv_spelling_errors
 ff  mv_field_file
 fi  mv_search_file
 fm  mv_first_match
 fn  mv_field_names
 hs  mv_head_skip
 ix  mv_index_delim
 lb  mv_search_label
 lf  mv_like_field
 lo  mv_list_only
 lr  mv_search_line_return
 ls  mv_like_spec
 ma  mv_more_alpha
 mc  mv_more_alpha_chars
 md  mv_more_decade
 ml  mv_matchlimit
 mm  mv_max_matches
 MM  mv_more_matches
 mp  mv_profile
 ms  mv_min_string
 ne  mv_negate
 ng  mv_negate
 np  mv_nextpage
 nu  mv_numeric
 op  mv_column_op
 os  mv_orsearch
 pf  prefix
 ra  mv_return_all
 rd  mv_return_delim
 rf  mv_return_fields
 rn  mv_return_file_name
 rr  mv_return_reference
 rs  mv_return_spec
 se  mv_searchspec
 sf  mv_search_field
 sg  mv_search_group
 si  mv_search_immediate
 sm  mv_start_match
 sp  mv_search_page
 sq  mv_sql_query
 sr  mv_search_relate
 st  mv_searchtype
 su  mv_substring_match
 tf  mv_sort_field
 to  mv_sort_option
 un  mv_unique
 va  mv_value

These can be treated just the same as form variables on the page, except that they can't contain a new line. If using the multi-line method of specification, the characters will automatically be escaped for a URL.

IMPORTANT NOTE: An incompatibility in earlier Interchange catalogs is specifying [page scan/se=searchstring]. This is interpreted by the parser as [page scan/se="searchstring"] and will cause a bad URL. Change this to [page scan se=searchstring], or perhaps better yet:

   [page search="
                   se=searchstring
           "]

A one-click search may be specified in three different ways.

Original

         [page scan se=Surreal/se=Gogh/os=yes/su=yes/sf=artist/sf=category]
            Van Gogh -- compare to surrealists
         </a>

Multi-Line

            [page scan
                se="Van Gogh"
                sp=lists/surreal
                os=yes
                su=yes
                sf=artist
                sf=category
            ] Van Gogh -- compare to surrealists </a>

Ampersand

         [page href=scan se="Van Gogh"&sp=lists/surreal&os=yes&su=yes&sf=artist]
            Van Gogh -- compare to surrealists
         </a>

53.8. Setting Display Options with mv_value

A value can be specified that will be set in the link with the mv_value parameter. It takes an argument of var=value, just as setting a normal variable in an Interchange profile. Actually mv_value is a misnomer, it will almost never be used in a form where variable values can be set. Always specify it in a one-click search with va=var=value. Example:

   [page href=scan
         arg="se=Renaissance
              se=Impressionists
              va=category_name=Renaissance and Impressionist Paintings
              os=yes"]Renaissance and Impressionist Paintings</a>

Display the appropriate category on the search results page with [value category_name].

53.9. In-Page Searches

To specify a search inside a page with the [search-region parameters*] tag. The parameters are the same as the one-click search, and the output is always a newline-separated list of the return objects, by default, a series of item codes.

The [loop ...] tag directly accepts a search parameter. To search for all products in the categories "Americana" and "Contemporary," do:

   [loop search="
       se=Americana
       se=Contemporary
       os=yes
       sf=category9
       "]
   Artist: [loop-field artist]<BR>
   Title: [loop-field title]<P>
   [/loop]

The advantage of the in-page search is that searches can be embedded within searches, and there can be straight unchanging links from static HTML pages.

To place an in-page search with the full range of display in a normal results page, use the [search-region] tag the same as above, except that [search-list], [more-list], and [more] tags can be placed within it. Use them to display and format the results, including paging. For example:

   [search-region  more=1
                   search="
                        se=Americana
                        sf=category
                        ml=2
                   "]
   [more-list][more][/more-list]
   [search-list]
   [page [item-code]]
       [item-field title]<A>, by [item-field artist]
   [/search-list]
   [no-match]
       Sorry, no matches for [value mv_searchspec].
   [/no-match]
   [/search-region]


Note: The [item-code] above does not need to be quoted because it is replaced before the [page ...] tag is interpolated. If building large lists, this is worth doing because unquoted tags are twice as fast to parse.

To use the same page for search paging, make sure to set the sp=page parameter.

53.10. Search Profiles

An unlimited number of search profiles can be predefined that reside in a file or files. To use this, make up a series of lines like:

mv_search_field=artist
mv_search_field=category
mv_orsearch=yes

These correspond to the Interchange search variables that can be set on a form. Set it right on the page that contains the search.

[set artist_profile]
mv_search_field=artist
mv_search_field=category
mv_orsearch=yes
[/set]

This is the same:

[set artist_profile]
sf=artist
sf=category
os=yes
[/set]

Then, in the search form, set a variable with the name of the profile:

   <INPUT TYPE=hidden NAME=mv_profile VALUE=artist_profile>

In a one-click search, use the mp modifier:

[page scan se=Leonardo/mp=artist_profile]A left-handed artist</a>

They can also be placed in a file. Define the file name in the SearchProfile directive. The catalog must be reconfigured for Interchange to read it. The profile is named by placing a name following a __NAME__ pragma:

 __NAME__ title_search

The __NAME__ must begin the line, and be followed by whitespace and the name.

The special variable mv_last stops interpretation of search variables. The following variables are always interpreted:

   mv_dict_look
   mv_searchspec

Other than that, if mv_last is set in a search profile, and there are other variables on the search form, they will not be interpreted.

To place multiple search profiles in the same file, separate them with __END__, which must be on a line by itself.

53.11. Search Reference

The supplied simple/srchform.html and simple/results.html pages show example search forms. Modify them to present the search in any way desired. Be careful to use the proper variable names for passing to Interchange. It is also necessary to copy the hidden variables as-is. They are required to interpret the request as a search.


Note: The following definitions frequently refer to field name and column and column number. All are the references to the columns of a searched text file as separated by delimiter characters.

The field names can be specified in several ways.

ProductFiles

Other database files

Other files

Fields can also always be specified by an integer column number, with 0 as the first column.

mv_all_chars

mv_base_directory

            [set /directory/name]1[/set]

mv_begin_string

mv_cache_key

mv_case

mv_column_op

        !=              Not equal to
        !~              Not matching regular expression
        <               Less than
        <=              Less than or equal to
        <>              Not equal to
        =               Equal to
        ==              Equal to
        =~              Matching regular expression
        >               Greater than
        >=              Greater than or equal to
        em              Exact match
        eq              Equal to
        ge              Greater than or equal to
        gt              Greater than
        le              Less than or equal to
        lt              Less than
        ne              Not equal to
        rm              Matching regular expression
        rn              Not matching regular expression

Note that several of the operators are the same. They do either numeric or string comparisons based on the status of mv_numeric (alias nu) for that column.

mv_coordinate

mv_dict_end

mv_dict_fold


Note: This is the reverse sense from mv_case.

mv_dict_limit


Note: The order of this and the mv_dict_end variable is significant. Each will overwrite the other.

            <INPUT TYPE=hidden NAME=mv_dict_limit  VALUE=category>
            <INPUT TYPE=hidden NAME=mv_search_file VALUE="products.txt">
            <INPUT TYPE=hidden NAME=mv_dict_limit    VALUE="-1">
            <INPUT TYPE=hidden NAME=mv_search_file   VALUE="products.txt.category">
            <INPUT TYPE=hidden NAME=mv_return_fields VALUE="1">
            Search for
            <SELECT NAME=mv_dict_limit>
            <OPTION> author
            <OPTION> title
            </SELECT> beginning with <INPUT NAME=mv_dictlook>

mv_dict_look

mv_dict_order

mv_doit

mv_exact_match

mv_field_file

mv_field_names


Note: Use this on the product database only if planning on both pre-sorting with mv_sort_field and then post-sorting with [sort]field:opt[/sort].

mv_first_match

mv_head_skip

mv_index_delim

mv_like_field

mv_like_spec

mv_matchlimit

mv_max_matches

mv_min_string

mv_negate

mv_orsearch

mv_profile

mv_record_delim

mv_return_fields

As with SQL queries, you can use the '*' shortcut to return all fields. For example:

    [loop search="fi=nation/ra=yes/rf=*"]

when used with a hypothetical 'nation' table would be equivalent to:

    [loop search="
          fi=nation
          ra=yes
          rf=code,sorder,region,name,tax
    "]

as well as:

    [loop search="fi=nation/ra=yes/rf=0,1,2,3,4"]

and:

    [query sql="select * from nation"][/query]

However, you probably rarely need to use every single field in a row. For maximum maintainability and execution speed the best practice is to list by name only the fields you want returned.

mv_return_spec

mv_search_field

mv_search_file

mv_search_match_count

mv_search_page

mv_searchspec

mv_searchtype

mv_small_data

Tells the search engine that there is a small amount of data in the file and that it should perform the search function on every line.

Normally, when Interchange can find a fixed search expression it produces a "screening" function which will allow records to be quickly rejected when they don't match. If there are less than 50 records in the file or database, this may be counterproductive.

mv_sort_field


Note: If specifying a sort for the product database, mv_field_names must be specified if doing a fieldname-addressed post-sort.

mv_sort_option

mv_spelling_errors

mv_substring_match

mv_unique

mv_value

53.12. The Results Page

Once a search has been completed, there needs to be a way of presenting the output. By default, the SpecialPage search is used. It is set to results in the distribution demo, but any number of search pages can be specified by passing the value in the search form specified in the variable mv_search_page.

On the search page, some special Interchange tags are used to format the otherwise standard HTML. Each of the iterative tags is applied to every code returned from the search. This is normally the product code, but could be a key to any of the arbitrary databases. The value placed by the [item-code] tag is set to the first field returned from the search.

The basic structure looks like this:

[search-region]
[search-list]
    your iterating code, once for each match
[/search-list]
[no-match]
    Text / tags to be output if no matches found (optional but recommended)
[/no-match]
[more-list]
    More / paging area (optional)
[/more-list]
[/search-region]

Tip for catalogs upgraded from Minivend 3: A [search-list][/search-list] must always be surrounded by a [search-region][/search-region] pair. This is a change from Minivend 3.

[search-list]

            [search-region prefix=my]
            [search-list]
                SKU:   [my-code]
                Title: [my-data products title]
            [/search-list]
            [/search-region]
         [item-alternate N] true [else] false [/else] [/item-alternate]
         [if-item-param named_field] true [else] false [/else] [/if-item-param]
         [item-param named_field]
         [if-item-pos N] true [else] false [/else] [/if-item-pos]
         [item-pos N]
         [if-item-field products_field] true [else] false [/else] [/if-item-field]
         [item-field products_column]
         [item-increment]
         [item-accessories]
         [item-code]
         [item-description]
         [if-item-data table column] true [else] false [/else] [/if-item-data]
         [item-data table column]
         [item-price N* noformat=1*]
         [item-calc] [/item-calc]
         [item-change marker]
                [condition]variable text[/condition]
                true
                [else] false [/else]
         [/item-change marker]
         [item-last] condition [/item-last]
         [item-next] condition [/item-next]


Note: those that reference the shopping cart do not apply, i.e., [item-quantity], [item-modifier ...] and friends.

[/search-list]

[no-match]

[/no-match]

[sort database:field:option* database:field:option*]

[item-change marker]

         <TABLE>
         <TR><TH>Category</TH><TH>Subcategory</TH><TH>Product</TH></TR>
         [search-list]
         <TR>
            <TD>
                 [item-change cat]
        
                 [condition][item-field category][/condition]
        
                         [item-field category]
                 [else]
                         &nbsp;
                 [/else]
                 [/item-change cat]
            </TD>
            <TD>
                 [item-change subcat]
        
                 [condition][item-field subcategory][/condition]
        
                         [item-field subcategory]
                 [else]
                         &nbsp;
                 [/else]
                 [/item-change subcat]
            </TD>
            <TD> [item-field name] </TD>
         [/search-list]
         </TABLE>

[/item-change marker]

[matches]

[match-count]

[more-list next_img* prev_img* page_img* border* border_current*]

             Previous   <IMG SRC="prev.gif" Border=3>
             Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
             Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
             Next       <IMG SRC="next.gif" Border=3>
             Previous   <IMG SRC="prev.gif">
             Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
             Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
             Next       <IMG SRC="next.gif">
             Previous   <IMG SRC="prev.gif" Border=0>
             Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
             Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
             Next       <IMG SRC="next.gif" Border=0>
            [more-list]
            [first-anchor] First [/first-anchor]
            [next-anchor] Forward | [/next-anchor]
            [prev-anchor] Back [/prev-anchor]
            [last-anchor] Last [/last-anchor]
            [page-anchor] Page $PAGE$ (matches $MINPAGE$-$MAXPAGE$) | [/page-anchor]
            [more]
            [/more-list]
            $PAGE$       Page number
            $MINPAGE$    Minimum match on page
            $MAXPAGE$    Maximum match on page
          [link-template]<a href="$URL$" target="_top">$ANCHOR$</a>[/link-template]
            $URL$      The URL for the 'more' page in question
            $ANCHOR$   The page number or the word "Next" or "Previous"
                           for the link in question.
          Previous 1 2 3 4 5 6 7 8 9 10 [more>>] Next
          Previous [<<more] 11 12 13 14 15 16 17 18 19 20 [more>>] Next
          Previous (lower) 11 12 13 14 15 16 17 18 19 20 (higher) Next

[/more-list]

[more]

            Previous 1 2 3 4 5 6 Next

[process-search]

54. Sorting

Interchange has standard sorting options for sorting the search lists, loop lists, and item lists based on the contents of database fields. In addition, it adds list slices for limiting the displayed entries based on a start value and chunk size (or start and end value, from which a chunk size is determined). All accept a standard format sort tag which must be directly after the list call:

   [loop 4 3 2 1]
   [sort -2 +2]
       [loop-code]
   [/loop]

   [search-list]
   [sort products:category:f]
       [item-price] [item-description]<BR>
   [/search-list]

   [item-list]
   [sort products:price:rn]
       [item-price] [item-code]<BR>
   [/item-list]

   [loop search="ra=yes"]
   [sort products:category products:title]
   [loop-field category] [loop-field title] <BR>
   [/loop]

All sort situations, [search list], [loop list], [tag each table], and [item-list], take options of the form:

 [sort database:field:option* -n +n =n-n ... ]

database

field

option

          f   case-insensitive sort (folded) (mutually exclusive of n)
          n   numeric order (mutually exclusive of f)
          r   reverse sort

-n

+n

=n-n

...

Multiple levels of sort are supported, and database boundaries on different sort levels can be crossed. Cross-database sorts on the same level are not supported. If using multiple product databases, they must be sorted with embedded Perl. This is actually a feature in some cases, all items in a used database can be displayed before or after new ones in products.

Examples, all based on the simple demo:

Loop list

            [loop 00-0011 19-202 34-101 99-102]
            [sort products:title]
                [loop-code] [loop-field title]<BR>
            [/loop]
            34-101 Family Portrait
            00-0011 Mona Lisa
            19-202 Radioactive Cats
            99-102 The Art Store T-Shirt
            [loop 00-0011 19-202 34-101 99-102]
            [sort products:title -3 +2]
                [loop-code] [loop-field title]<BR>
            [/loop]
            19-202 Radioactive Cats
            99-102 The Art Store T-Shirt

Search list

            [search-list]
            [sort products:artist products:title:rf]
                [item-field artist] [item-field title]<BR>
            [/search-list]
            Gilded Frame
            Grant Wood American Gothic
            Jean Langan Family Portrait
            Leonardo Da Vinci Mona Lisa
            Salvador Dali Persistence of Memory
            Sandy Skoglund Radioactive Cats
            The Art Store The Art Store T-Shirt
            Vincent Van Gogh The Starry Night
            Vincent Van Gogh Sunflowers
            [search-list]
            [sort products:artist products:title:rf =6-10]
                [item-field artist] [item-field title]<BR>
            [/search-list]
            Sandy Skoglund Radioactive Cats
            The Art Store The Art Store T-Shirt
            Vincent Van Gogh The Starry Night
            Vincent Van Gogh Sunflowers

Shopping cart

            [item-list]
            [sort products:price:rn]
                [item-price] [item-code]<BR>
            [/item-list]

Complete database contents

            [tag each products]
            [sort products:category products:title]
            [loop-field category] [loop-field title] <BR>
            [/tag]

Note that large lists may take some time to sort. If a product database contains many thousands of items, using the [tag each products] sort is not recommended unless planning on caching or statically building pages.

55. Shipping

Interchange has a powerful custom shipping facility that performs UPS and other shipper lookups, as well as a flexible rule-based facility for figuring cost by other methods.

55.1. Shipping Cost Database

The shipping cost database (located in ProductDir/shipping.asc) is a tab-separated ASCII file with eight fields: code, text description, criteria (quantity or weight, for example), minimum number, maximum number, and cost, query, and options. None of the fields are case-sensitive.

To define the shipping database in a catalog configuration file, set the Variable MV_SHIPPING to what would be its contents.

To set the file to be something other than shipping.asc in the products directory, set the Special directive:

   Special  shipping.asc  /home/user/somewhere/shipping_defs

There are two styles of setting which can be mixed in the same file. The first is line-based and expects six or more TAB-separated fields. They would look like:

default No shipping weight  0   99999999    0

upsg    UPS Ground  weight  0   0   e Nothing to ship!
upsg    UPS Ground  weight  0   150 u Ground [default zip 98366] 3.00
upsg    UPS Ground  weight  150 999999  e @@TOTAL@@ lbs too heavy for UPS

The second is a freeform method with a mode: Description text introducing the mode line. The special encoding is called out by indented parameters. The below is identical to the above:

   upsg: UPS Ground
       criteria    weight
       min         0
       max         0
       cost        e Nothing to ship!

       min         0
       max         150
       cost        u
       table       2ndDayAir
       geo         zip
       default_geo 98366
       adder       3

       min         150
       max         999999
       cost        e @@TOTAL@@ lbs too heavy for UPS

The second format has several advantages. Multiple lines can be spanned with the <<HERE document format, like so:

   upsg: UPS Ground
       criteria    <<EOF
   [perl]
       return 'weight' if $Values->{country} eq 'US';
       return 'weight' if ! $Values->{country};
       # Return blank, don't want UPS
       return '';
   [/perl]
   EOF

The definable fields are, in order, for the tab-separated format:

MODE

DESCRIPTION

CRITERIA

MINIMUM

MAXIMUM

COST

           f       Formula (ITL tags OK, evaluated as Perl)
           x       Multiplied by a number
           [uA-Z]  UPS-style lookup
           m       Interchange chained cost lookup (all items summed together)
           i       Interchange chained cost lookup (items summed individually)

NEXT

ZONE

QUERY

QUAL

PERL

TOTAL

OPT

55.2. Criteria Determination

The criteria field varies according to whether it is the first field in the shipping file exactly matching the mode identifier. In that case, it is called the main criterion. If it is in subsidiary shipping lines matching the mode (with optional appended digits), it is called a qualifying criterion. The difference is that the main criterion returns the basis for the calculation (i.e., weight or quantity), while the qualifying criterion determines whether the individual line may match the conditions.

The return must be one of:

quantity

o <field name> or <table>::<field name>

o n.nn


IMPORTANT NOTE: The above only applies to the first field that matches the shipping mode exactly. Following criteria fields contain qualifier matching strings.

55.3. Shipping Calculation Modes

There are eight ways that shipping cost may be calculated. The method used depends on the first character of the cost field in the shipping database.

N.NN (digits)

e

f

i

m

u

x

A-Z

55.4. How Shipping is Calculated

  1. The base code is selected by reading the value of mv_shipmode in the user session. If it has not been explicitly set, either by means of the DefaultShipping directive or by setting the variable on a form (or in an order profile), it will be default.
    The mv_shipmode must be in the character class [A-Za-z0-9_]. If there are spaces, commas, or nulls in the value, they will be read as multiple shipping modes.
      The criterion field is found. If it is quantity, it is the total quantity of items on the order form. If it is any other name, the criterion is calculated by multiplying the return value from the product database field for each item in the shopping cart, multiplied by its quantity. If the lookup fails due to the column or row not existing, a zero cost will be returned and an error is sent to the catalog error log. If a number is returned from an Interchange tag, that number is used directly.
      Entries in the shipping database that begin with the same string as the shipping mode are examined. If none is found, a zero cost is returned and an error is sent to the catalog error log.


Note: The same mode name may be used for all lines in the same group, but the first one will contain the main criteria.

  1. The value of the accumulated criteria is examined. If it falls within the minimum and maximum, the cost is applied.
  2. If the cost is fixed, it is simply added.
  3. If the cost field begins with an x, the cost is multiplied by the accumulated criterion, i.e., price, weight, etc.
  4. If the cost field begins with f, the formula following is applied. Use @@TOTAL@@ as the value of the accumulated criterion.
  5. If the cost field begins with u or a single letter from A-Z, a UPS-style lookup is done.
  6. If the cost field begins with s, a Perl subroutine call is made.
  7. If the cost field begins with e, zero cost is returned and an error placed in the session ship_message field, available as [data session ship_message].

Here is an example shipping file using all of the methods of determining shipping cost.


Note: The columns are lined up for reading convenience. The actual entries should have one tab between fields.

global Option   n/a               0   0  g PriceDivide

rpsg  RPS     quantity         0   0     R RPS products/rps.csv
rpsg  RPS     quantity         0   5     7.00
rpsg  RPS     quantity         6   10    10.00
rpsg  RPS     quantity         11  150   x .95

usps  US Post price            0   0     0
usps  US Post price            0   50    f 7 + (1 * @@TOTAL@@ / 10)
usps  US Post price            50  100   f 12 + (.90 * @@TOTAL@@ / 10)
usps  US Post price            100 99999 f @@TOTAL@@ * .05

upsg  UPS     weight [value state]  0   0   e Nothing to ship.
upsg  UPS     AK HI            0   150   u upsg [default zip 980] 12.00 round
upsg  UPS                      0   150   u Ground [default zip 980] 2.00 round
upsg  UPS                      150 9999  e @@TOTAL@@ lb too heavy for UPS

upsca UPS/CA  weight           0   0     c C UPS_Canada products/can.csv
upsca UPS/CA  weight           -1   -1   o PriceDivide=0
upsca UPS/CA  weight           0   150   C upsca [default zip A7G] 5.00
upsca UPS/CA  weight           150 99999 e @@TOTAL@@ lb too heavy for UPS

global

rpsg

usps

upsg

            1. Weight
            2. The zip/postal code of the recipient of which only
               the first three digits are used.
            3. A fixed amount to add to the cost found in the UPS
               tables (use 0 as a placeholder if specifying roundup)
            4. If set to 'round,' will round the cost up to the next
               integer monetary unit.
            UPSZoneFile  products/450.csv
            Database  Ground  Ground.csv  CSV

A simple shipping cost qualification can be appended to a UPS lookup. If any additional parameters are present after the five usual ones used for UPS lookup, they will be interpreted as a Perl subroutine call. The syntax is the same as if it was encased in the tag [perl] [/perl], but the following substitutions are made prior to the call:

            @@COST@@  is replaced with whatever the UPS lookup returned
            @@GEO@@   is replaced with the zip (or other geo code)
            @@ADDER@@ is replaced with the defined adder
            @@TYPE@@  is replaced with the UPS shipping type
            @@TOTAL@@ is replaced with the total weight

upsca

Up to 27 different lookup zones can be defined in the same fashion, allowing for multiple zone files. If one of the cost lines (the last field) in the shipping.asc file begins with a c, it configures another lookup zone which must be lettered from A to Z. It takes the format:

            c X name file* length* multiplier*
            c U UPS products/450.csv 3 1

55.5. More On UPS-Style Lookup

The UPS-style lookup uses two files for its purposes, both of which need to be in a format like UPS distributes for US shippers.

The zone file is a file that is usually specific to the originating location. For US shippers shipping to US locations, it is named for the first three digits of the originating zip code with a CSV extension. For example, 450.csv.

It has a format similar to:

   low - high, zone,zone,zone,zone

The low entry is the low bound of the geographic location; high is the high bound. (By geographic location, the zip code is meant.) If the first digits of the zip code, compared alphanumerically, fall between the low and high values, that zone is used as the column name for a lookup in the rate database. The weight is used as the row key.

The first operative row of the zone file (one without leading quotes) is used to determine the zone column name. In the US, it looks something like:

 Dest. ZIP,Ground,3 Day Select,2nd Day Air,2nd Day Air A.M.,\
  Next Day Air Saver,Next Day Air

Interchange strips all non-alpha characters and comes up with:

 DestZIP,Ground,3DaySelect,2ndDayAir,2ndDayAirAM,NextDayAirSaver,NextDayAir

Therefore, the zone column (shipping type) that would be used for UPS ground would be "Ground," and that is what the database should be named. To support the above, use a shipping.asc line that reads:

   upsg  UPS Ground  weight  0  150  u Ground [default zip 983]

and a catalog.cfg database callout of:

   Database  Ground  Ground.csv  CSV

These column names can be changed as long as they correspond to the identifier of the rate database.

The rate database is a standard Interchange database. For U.S. shippers, UPS distributes their rates in a fairly standard comma-separated value format, with weight being the first (or key) column and the remainder of the columns corresponding to the zone which was obtained from the lookup in the zone file.

To adapt other shipper zone files to Interchange's lookup, they will need to fit the UPS US format. (Most of the UPS international files don't follow the U.S. format). For example, the 1998 Ohio-US to Canada file begins:

   Canada Standard Zone Charts from Ohio
   Locate the zone by cross-referencing the first three
   characters of the destination Postal Code in the Postal
   Range column.

   Postal Range  Zone
   A0A  A9Z      54
   B0A  B9Z      54
   C0A  C9Z      54
   E0A  E9Z      54
   G0A  G0A      51
   G0B  G0L      54
   G0M  G0S      51
   G0T  G0W      54

It will need to be changed to:

   Destination,canstnd
   A0A-A9Z, 54
   B0A-B9Z, 54
   C0A-C9Z, 54
   E0A-E9Z, 54
   G0A-G0A, 51
   G0B-G0L, 54
   G0M-G0S, 51
   G0T-G0W, 54

Match it with a canstnd CSV database that looks like this:

   Weight,51,52,53,54,55,56
   1,7.00,7.05,7.10,11.40,11.45,11.50
   2,7.55,7.65,7.75,11.95,12.05,12.10
   3,8.10,8.15,8.40,12.60,12.70,12.85
   4,8.65,8.70,9.00,13.20,13.30,13.55
   5,9.20,9.25,9.75,13.85,13.85,14.20
   6,9.70,9.85,10.35,14.45,14.50,14.90
   7,10.25,10.40,11.10,15.15,15.15,15.70
   8,10.80,10.95,11.70,15.70,15.75,16.35
   9,11.35,11.55,12.30,16.40,16.45,17.20

It is called out in catalog.cfg with:

   Database canstnd canstnd.csv CSV

With the above, a 4-pound shipment to postal code E5C 4TL would yield a cost of 13.20.

55.6. Geographic Qualification

If the return value in the main criterion includes whitespace, the remaining information in the field is used as a qualifier for the subsidiary shipping modes. This can be used to create geographic qualifications for shipping, as in:

upsg  UPS Ground  weight [value state]  0   0    e No items selected
upsg  UPS Ground  AK HI                 0   150  u Ground [value zip] 12.00
upsg  UPS Ground                        0   150  u Ground [value zip] 3.00

If upsg is the mode selected, the value of the user session variable state is examined to see if it matches the geographic qualification on a whole-word boundary. If it is AK or HI, UPS Ground with an adder of 12 will be selected. If it "falls through," UPS Ground with an adder of 3 will be selected.

55.7. Handling Charges

Additional handling charges can be defined in the shipping file by setting the form variable mv_handling to a space, comma, or null-separated set of valid shipping modes. The lookup and charges are created in the same fashion, and the additional charges are added to the order. (The user is responsible for displaying the charge on the order report or receipt with a [shipping handling] tag, or the like.) All of the shipping modes found in mv_handling will be applied. If multiple instances are found on a form, the accordingly null-separated values will all be applied. NOTE: This should not be done in an item-list unless the multiple setting of the variables is accounted for.

To only process a handling charge once, do the following:

   [item-list]
   [if-item-field very_heavy]
   [perl values]
       return '' if $Values->{mv_handling} =~ /very_heavy/;
       return "<INPUT TYPE=hidden NAME=mv_handling VALUE=very_heavy>";
   [/perl]
   [/if-item-field]
   [/item-list]

A non-blank/non-zero value in the database field will trigger Perl code which will only set mv_handling once.

55.8. Default Shipping Mode

If a default shipping mode other than default is desired, enter it into the DefaultShipping directive:

   DefaultShipping     upsg

This will make the entry on the order form checked by default when the user starts the order process, if it is put in the form:

 <INPUT TYPE=RADIO NAME=mv_shipmode VALUE=upsg [checked mv_shipmode upsg]>

To force a choice by the user, make mv_shipmode a required form variable (with RequiredFields or in an order profile) and set DefaultShipping to zero.

56. User Database

Interchange has a user database function which allows customers to save any pertinent values from their session. It also allows the setting of database or file access control lists for use in controlling access to pages and databases on a user-by-user basis.

The database field names in the user database correspond with the form variable names in the user session. If there is a column named address, when the user logs in the contents of that field will be placed in the form variable address, and will be available for display with [value address]. Similarly, the database value is available with [data table=userdb column=address key=username].

The ASCII file for the database will not reflect changes unless the file is exported with [tag export userdb][/tag]. It is not advisable to edit the ASCII file, as it will overwrite the real data that is in the DBM table. User logins and changes would be lost. Note: This would not happen with SQL, but editing the ASCII file would have no effect. It is recommended that the NoImport configuration directive be set accordingly.

The field names to be used are not set in concrete. They may be changed with options. Fields may be added or subtracted at any time. Most users will choose to keep the default demo fields for simplicity sake, as they cover most common needs. As distributed in the demo, the fields are:

   code
   accounts
   acl
   address
   address_book
   b_address
   b_city
   b_country
   b_name
   b_nickname
   b_phone
   b_state
   b_zip
   carts
   city
   country
   db_acl
   email
   email_copy
   fax
   fax_order
   file_acl
   mv_credit_card_exp_month
   mv_credit_card_exp_year
   mv_credit_card_info
   mv_credit_card_type
   mv_shipmode
   name
   order_numbers
   p_nickname
   password
   phone_day
   phone_night
   preferences
   s_nickname
   state
   time
   zip

A few of those fields are special in naming, though all can be changed via an option. A couple of the fields are reserved for Interchange's use.


Note: If not running with PGP or other encryption for credit card numbers, which is never recommended, it is important that the mv_credit_card_info field be removed from the database.

The special database fields are:

   accounts         Storage for billing accounts book
   address_book     Storage for shipping address book
   b_nickname       Nickname of current billing account
   carts            Storage for shopping carts
   p_nickname       Nickname for current preferences
   preferences      Storage for preferences
   s_nickname       Nickname for current shipping address
   db_acl           Storage for database access control lists
   file_acl         Storage for file access control lists
   acl              Storage for simple integrated access control

If not defined, the corresponding capability is not available.


Note: The fields accounts, address_book, carts, and preferences should be defined as a BLOB type, if using SQL. This is also suggested for the acl fields if those lists could be large.

Reserved fields include:

   code        The username (key for the database)
   password    Password storage
   time        Last time of login

56.1. The [userdb ...] Tag

Interchange provides a [userdb ...] tag to access the UserDB functions.

[userdb
       function=function_name
       username="username"*
       assign_username=1
       username_mask=REGEX*
       password="password"*
       verify="password"*
       oldpass="old password"*
       crypt="1|0"*
       shipping="fields for shipping save"
       billing="fields for billing save"
       preferences="fields for preferences save"
       ignore_case="1|0"*
       force_lower=1
       param1=value*
       param2=value*
       ...
       ]

* Optional

It is normally called in an mv_click or mv_check setting, as in:

   [set Login]
   mv_todo=return
   mv_nextpage=welcome
   [userdb function=login]
   [/set]

   <FORM ACTION="[process]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_click VALUE=Login>
   Username <INPUT NAME=mv_username SIZE=10>
   Password <INPUT NAME=mv_password SIZE=10>
   </FORM>

There are several global parameters that apply to any use of the userdb functions. Most importantly, by default, the database table is set to be userdb. If another table name must be used, include a database=table parameter with any call to userdb. The global parameters (default in parentheses):

 database          Sets user database table (userdb)
 show              Show the return value of certain functions
                   or the error message, if any (0)
 force_lower       Force possibly upper-case database fields
                   to lower case session variable names (0)
 billing           Set the billing fields (see Accounts)
 shipping          Set the shipping fields (see Address Book)
 preferences       Set the preferences fields (see Preferences)
 bill_field        Set field name for accounts (accounts)
 addr_field        Set field name for address book (address_book)
 pref_field        Set field name for preferences (preferences)
 cart_field        Set field name for cart storage (carts)
 pass_field        Set field name for password (password)
 time_field        Set field for storing last login time (time)
 outboard          Set fields that live in another table
 outboard_key_col  Set field providing key for outboard tables
 expire_field      Set field for expiration date (expire_date)
 acl               Set field for simple access control storage (acl)
 file_acl          Set field for file access control storage (file_acl)
 db_acl            Set field for database access control storage (db_acl)
 indirect_login    Log in field if different than real username ('')

By default the system crypt() call will be used to compare the password. This is best for security, but the passwords in the user database will not be human readable.

If no critical information is kept and Interchange administration is not done via the UserDB capability, use the UserDB directive (described below) to set encryption off by default:

   UserDB   default   crypt   0

Encryption can still be set on by passing crypt=1 with any call to a new_account, change_pass, or login call.

If you are encrypting, and you wish to use MD5 to encrypt the passwords, set the md5 parameter:

UserDB default md5 1

56.2. Setting Defaults with the UserDB Directive

The UserDB directive provides a way to set defaults for the user database. For example, to save and recall the scratch variable tickets in the user database instead of the form variable tickets, set:

   UserDB   default   scratch  tickets

That makes every call to [userdb function=login] equivalent to [userdb function=login scratch=tickets].

To override that default for one call only, use [userdb function=login scratch="passes"].

To log failed access authorizations, set the UserDB profile parameter log_failed true:

   UserDB  default  log_failed 1

To disable logging of failed access authorizations (the default), set the UserDB profile parameter log_failed to 0:

   UserDB  default  log_failed 0

The UserDB directive uses the same key-value pair settings as the Locale and Route directives. If there are more than one set of defaults, set them in a hash structure:

   UserDB  crypt_case  <<EOF
   {
       'scratch'        => 'tickets',
       'crypt'          => '1',
       'ignore_case'    => '0',
   }
   EOF

   UserDB  default  <<EOF
   {
       'scratch'        => 'tickets',
       'crypt'          => '1',
       'ignore_case'    => '1',
   }
   EOF


Note: The usual here-document caveats apply. The "EOF" must be on a line by itself with no leading/trailing whitespace.

The last one to be set becomes the default.

The option profile selects the set to use. For usernames and passwords to be case sensitive with no encryption, pass this call:

   [userdb function=new_account profile=case_crypt]

The username and password will be stored as typed in, and the password will be encrypted in the database.

56.3. User Database Functions

The user database features are implemented as a series of functions attached to the userdb tag. The functions are:

login

logout

new_account

            [userdb function=new_account
                    username_mask="^[A-Z]*[0-9]"
                    ]
            [userdb function=new_account
                    username="[value mv_order_number]"
                    password="[value zip]"
                    verify="[value zip]"
                    database="orders"
                    ]

change_pass

set_shipping

            [userdb function=set_shipping nickname=Dad]

get_shipping

            [userdb function=get_shipping nickname=Dad]

get_shipping_names

            [set name=shipping_nicknames
                 interpolate=1]
              [userdb function=get_shipping_names show=1]
            [/set]

set_billing

            [userdb function=set_billing nickname=discover]

get_billing

            [userdb function=get_billing nickname=visa]

save

set_cart

            [userdb function=set_cart nickname=christmas]

get_cart

            [userdb function=get_cart nickname=mom_birthday]

set_acl

            [userdb function=set_acl location=cartcfg/editcart]
            [userdb function=set_acl location=cartcfg/editcart delete=1]
            [userdb function=set_acl location=cartcf/editcart show=1]

check_acl

            [if type=explicit
                compare="[userdb
                            function=check_acl
                            location=cartcfg/editcart]"
            ]
            [page cartcfg/editcart]Edit your cart configuration</a>
            [/if]

set_file_acl, set_db_acl

            [userdb function=set_file_acl
                    mode=rw
                    location=products/inventory.txt]

check_file_acl, check_db_acl

            [userdb function=check_db_acl
                    mode=w
                    location=inventory]
            [if type=explicit
                compare="[userdb
                            function=check_db_acl
                            mode=w
                            location=inventory]"
            ]
            [userdb function=set_acl location=cartcfg/edit_inventory]
            [page cartcfg/edit_inventory]You may edit the inventory database</a>
            [else]
            [userdb function=set_acl location=cartcfg/edit_inventory delete=1]
            Sorry, you can't edit inventory.
            [/if]

56.4. Address Book

Address_book is a shipping address book. The shipping address book saves information relevant to shipping the order. In its simplest form, this can be the only address book needed. By default these form values are included:

  s_nickname
  name
  fname
  lname
  address
  address1
  address2
  address3
  city
  state
  zip
  country
  phone_day
  mv_shipmode

The first field is always the name of the form variable that contains the key for the entry. The values are saved with the [userdb function=set_shipping] tag call, and are recalled with [userdb function=get_shipping]. A list of the keys available is kept in the form value address_book, suitable for iteration in an HTML select box or in a set of links.

To get the names of the addresses, use the get_shipping_names function:

   [userdb function=get_shipping_names]

By default, they are placed in the variable address_book. Here is a little snippet that builds a select box:

   <FORM ACTION="[process]" METHOD=POST>
   [userdb function=get_shipping_names]
   [if value address_book]
   <SELECT NAME="s_nickname">
   [loop arg="[value address_book]"] <OPTION> [loop-code] [/loop]
   </SELECT>
   <INPUT TYPE=submit NAME=mv_check VALUE="Recall Shipping">
   </FORM>

The same principle works with accounts, carts, and preferences.

To restore a cart based on the above, put in an mv_check routine:

   [set Recall Shipping]
   mv_todo=return
   mv_nextpage=ord/basket
   [userdb function=get_shipping nickname="[value s_nickname]"]
   [/set]

When the mv_check variable is encountered, the contents of the scratch variable Recall Shipping are processed and the shipping address information inserted into the user form values. This is destructive of any current values of those user session variables, of course.

To change the fields that are recalled or saved, use the shipping parameter:

   [userdb function=get_shipping
           nickname=city_and_state
           shipping="city state"]

Only the values of the city and state variables will be replaced.

56.5. Accounts Book

The accounts book saves information relevant to billing the order. By default these form values are included:

  b_nickname
  b_name
  b_fname
  b_lname
  b_address
  b_address1
  b_address2
  b_address3
  b_city
  b_state
  b_zip
  b_country
  b_phone
  purchase_order
  mv_credit_card_type
  mv_credit_card_exp_month
  mv_credit_card_exp_year
  mv_credit_card_info

The values are saved with the [userdb function=set_billing] tag call, and are recalled with [userdb function=get_billing]. A list of the keys available is kept in the form value accounts, suitable for iteration in an HTML select box or in a set of links.

56.6. Preferences

Preferences are miscellaneous session information. They include, by default, the following fields:

   email
   fax
   phone_night
   fax_order
   email_copy

The field p_nickname acts as a key to select the preference set. To change the values that are included with the preferences parameter:

   [userdb function=set_preferences
           preferences="email_copy email fax_order fax"]

or in catalog.cfg:

   UserDB default preferences "mail_list email fax_order music_genre"

56.7. Carts

The contents of shopping carts may be saved or recalled in much the same fashion. See the Simple demo application ord/basket.html page for an example.

56.8. Controlling Page Access With UserDB

Interchange can implement a simple access control scheme with the user database. Controlled pages must reside in a directory which has a file named .access that is zero bytes in length. (If it is more than 0 bytes, only the RemoteUser or MasterHost may access files in that directory.)

Set the following variables in catalog.cfg:

   Variable   MV_USERDB_ACL_TABLE  userdb
   Variable   MV_USERDB_ACL_COLUMN acl

The MV_USERDB_ACL_TABLE is the table which controls access, and likewise the MV_USERDB_ACL_TABLE names the column in that database which will be checked for authorization.

The database entry should contain the complete Interchange-style page name of the page to be allowed. It will not match substrings.

For example, if the user flycat followed this link:

   <A HREF="[area cartcfg/master_edit]">Edit</A>

Access would be allowed if the contents of the userdb were:

   code    acl
   flycat  cartcfg/master_edit

and disallowed if it were:

   code    acl
   flycat  cartcfg/master_editor

Access can be enabled with:

   [userdb function=set_acl location="cartcfg/master_edit"]

Access can be disallowed with:

   [userdb function=set_acl
           delete=1
           location="cartcfg/master_edit"]

Of course, a pre-existing database with the ACL values will work as well. It need not be in the UserDB setup.

56.9. Using more than one table

You can save/retrieve userdb information from more than one table with the outboard specifier. It is a quoted key-value comma-separated series of field specifications. For instance, if the billing address is to be stored in a separate table named "billing", you would do:

        UserDB  default outboard  <<EOF
            "b_fname=billing::first_name,
             b_lname=billing::last_name,
             b_address1=billing::address1,
             b_address2=billing::address2,
                         b_etc=billing::etc"
        EOF

When the user logs in, Interchange will access the first_name field in table billing to get the value of b_fname. When the values are saved, it will be saved there as well. If you wish to make the fields read-only, just set UserDB default scratch "b_fname b_lname ..." and the values will be retrieved/saved from there. To initialize the values for a form, you could do a function after the user logs in:

 [calc]
        my @s_fields = grep /\S/, split /[\s,\0]+/, $Config->{UserDB}{scratch};
        for(@s_fields) {
                $Values->{$_} = $Scratch->{$_};
        }
        return;
 [/calc]

If the fields in the outboard table use another key besides username, you can specify the column in the userdb that contains the key value:

        UserDB  default  outboard_key_col   account_id

57. Tracking and Back-End Order Entry

Interchange allows the entry of orders into a system through one of several methods. Orders can be written to an ASCII file or formatted precisely for email-based systems. Or they can go directly into an SQL or DBM database. Finally, embedded Perl allows completely flexible order entry, including real-time credit card verification and settlement.

57.1. ASCII Backup Order Tracking

If AsciiTrack is set to a legal file name (based in VendRoot unless it has a leading "/"), a copy of the order is saved and sent in an email.

If the file name string begins with a pipe "|", a program will be run and the output "piped" to that program. This allows easy back-end entry of orders with an external program.

57.2. Database Tracking

Once the order report is processed, the order is complete. Therefore, it is the ideal place to put Interchange tags that make order entries in database tables.

A good model is to place a single record in a database summarizing the order and a series of lines that correspond to each line item in the order. This can be in the same database table. If the order number itself is the key for the summary, a line number can be appended to the order number to show each line of the order.

The following would summarize a sample order number S00001 for part number 00-0011 and 99-102:

   code     order_number part_number  quantity   price    shipping  tax
   S00001   S00001                    3          2010     12.72     100.50
   S00001-1 S00001       00-0011      2          1000     UPS       yes
   S00001-2 S00001       99-102       1          10       UPS       yes

Fields can be added where needed, perhaps with order status, shipping tracking number, address, customer number, or other information.

The above is accomplished with Interchange's [import ....] tag using the convenient NOTES format:

   [set import_status]
   [import table=orders type=LINE continue=NOTES]

   code: [value mv_order_number]
   order_number: [value mv_order_number]
   quantity: [nitems]
   price: [subtotal noformat=1]
   shipping: [shipping noformat=1]
   tax: [salestax noformat=1]

   [/import]

   [item-list]
   [import table=orders type=LINE continue=NOTES]

   code: [value mv_order_number]-[item-increment]
   order_number: [value mv_order_number]
   quantity: [item-quantity]
   price: [item-price noformat=1]
   shipping: [shipping-description]
   tax: [if-item-field nontaxable]No[else]Yes[/else][/if]

   [/import][/item-list]

57.3. Order Routing

Interchange can send order emails and perform custom credit card charges and/or logging for each item. The Route directive is used to control this behavior, along with the mv_order_route item attribute.

If no Route is in the catalog, Interchange uses a default "mail out the order and show a receipt" model.

Routes are established with the Route directive, which is similar to the Locale directive. Each route is like a locale, so that key-value pairs can be set. Here is an example setting:

   Route  mail  pgp_key         0x67798115
   Route  mail  email           orders@akopia.com
   Route  mail  reply           service@akopia.com
   Route  mail  encrypt         1
   Route  mail  encrypt_program "/usr/bin/pgpe -fat -q -r %s"
   Route  mail  report          etc/report_mail


Note: Values with whitespace in them must be quoted.

You can also set the route in a valid Perl hash reference string:

   Route  mail <<EOR
   {
        pgp_key         => '0x67798115',
        email           => 'orders@akopia.com',
        reply           => 'service@akopia.com',
        encrypt         => 1,
        encrypt_program => q{/usr/bin/gpg -e -a -r '%s' --batch},
        report          => 'etc/report_mail',
  }
  EOR

This route would be used whenever the mail route was called by one of the three possible methods:

route called from master route

route set in item

route set in the form variable mv_order_route

The last route that is defined is the master route, by convention named main. Besides setting the global behavior of the routing, it provides some defaults for other routes. For example, if encrypt_program is set there, then the same value will be the default for all routes. Most settings do not fall through.

The attributes that can be set are:

attach

A list of routes which should be pushed on the stack of routes to run, after all currently scheduled routes are done. NOTE: cascades can cause endless loops, so only one setting is recommended, that being the main route.

commit

commit_tables

counter

credit_card

dynamic_routes

email

empty

This should be set if neither attach or email is set.

encrypt

encrypt_program

errors_to

expandable

extended

        Route  main   extended    { email => 'milton@akopia.com' }
        Route  main   email       papabear@minivend.com

The ultimate setting of email will be milton@akopia.com.

increment

individual_track

individual_track_ext

   individual_track_ext     .pgp

individual_track_mode

   individual_track_mode    0444

master

payment_mode

pgp_cc_key

pgp_key

profile

receipt

report

reply

rollback

rollback_tables

supplant

track

track_mode

   track_mode    0444

transactions

Individual item routing causes all items labeled with that route to be placed in a special sub-cart that will be used for the order report. This means that the [item-list] LIST [/item-list] will only contain those items, allowing operations to be performed on subsets of the complete order. The [subtotal], [salestax], [shipping], [handling], and [total-cost] tags are also affected.

Here is an example of an order routing:

   Route  HARD      pgp_key          0x67798115
   Route  HARD      email            hardgoods@akopia.com
   Route  HARD      reply            service@akopia.com
   Route  HARD      encrypt          1
   Route  HARD      report           etc/report_mail

   Route  SOFT      email            ""
   Route  SOFT      profile          create_download_link
   Route  SOFT      empty            1

   Route  mail      pgp_key          0x67798115
   Route  mail      email            orders@akopia.com
   Route  mail      reply            service@akopia.com
   Route  mail      encrypt          1
   Route  mail      report           etc/report_all

   Route  user      error_ok         1
   Route  user      email            email
   Route  user      reply            service@akopia.com
   Route  user      report           etc/user_copy

   Route  log       empty            1
   Route  log       report           etc/log_transaction
   Route  log       transactions     "transactions orderline inventory"
   Route  log       track            logs/log

   Route  main      supplant         1
   Route  main      receipt          etc/receipt.html
   Route  main      master           log mail user
   Route  main      cascade          log mail user
   Route  main      encrypt_program  "/usr/bin/gpg -e -a r '%s' --batch"

This will have the following behavior:

Order

Transactions

Failure

Encryption The mail order route and the HARD order route will be sent by email, and encrypted against different GPG key IDs. They will get their encrypt_program setting from the main route.

To set the order routing for individual items, some method of determining their status must be made and the mv_order_route attribute must be set. This could be set at the time of the item being placed in the basket, or have a database field called goods_type set to the appropriate value. The following example uses a Perl routine on the final order form:

  [perl table=products]
     my %route;
     my $item;
     foreach $item (@{$Items}) {
         my $code = $item->{code};
         my $keycode = $Tag->data('products', 'goods_type', $code);
         $item->{mv_order_route} = $keycode;
     }
     return;
  [/perl]

Now the individual items are labeled with a mv_order_route value which causes their inclusion in the appropriate order routing.

Upon submission of the order form, any item labeled HARD will be accumulated and sent to the e-mail address hardgoods@akopia.com, where the item will be pulled from inventory and shipped.

Any item labeled SOFT will be passed to the order profile create_download_link, which will place it in a staging area for customer download. (This would be supported by a link on the receipt, possibly by reading a value set in the profile).

58. SSL Support

Interchange has several features that enable secure ordering via SSL (Secure Sockets Layer). Despite their mystique, SSL servers are actually quite easy to operate. The difference between the standard HTTP server and the SSL HTTPS server, from the standpoint of the user, is only in the encryption and the specification of the URL; https: is used for the URL protocol specification instead of the usual http: designation.


IMPORTANT NOTE: Interchange attempts to perform operations securely, but no guarantees or warranties of any kind are made! Since Interchange comes with source code, it is fairly easy to modify the program to create security problems. One way to minimize this possibility is to record digital signatures, using MD5 or PGP or GnuPG, of interchange, interchange.cfg, and all modules included in Interchange. Check them on a regular basis to ensure they have not been changed.

Interchange uses the SecureURL directive to set the base URL for secure transactions, and the VendURL directive for normal non-secure transactions. Secure URLs can be enabled for forms through a form action of [process secure=1]. An individual page can be displayed via SSL with [page href=mvstyle_pagename secure=1]. A certain page can be set to be always secure with the AlwaysSecure catalog.cfg directive.

Interchange incorporates additional security for credit card numbers. The field mv_credit_card_number will not ever be written to disk.

To enable automated encryption of the credit card information, the directive CreditCardAuto needs to be defined as Yes. EncryptProgram also needs to be defined with some value, one which will, hopefully, encrypt the number. PGP is now recommended above all other encryption program. The entries should look something like:

 CreditCardAuto   Yes
 EncryptProgram   /usr/bin/pgpe -fat -r sales@company.com

See CreditCardAuto for more information on how to set the form variables.

59. Frequently Asked Questions

59.1. I can't get SQL to work: Undefined subroutine &Vend::Table::DBI::create ...

This probably means one of the following:

No SQL database.

No DBI.

            perl -MCPAN -e 'install DBI'

No DBD.

            perl -MCPAN -e 'install DBD::XXXXX'
            Adabas
            DB2
            Informix
            Ingres
            ODBC
            Oracle
            Pg
            Solid
            Sybase
            Unify
            XBase
            mSQL
            mysql
            use DBI;
            use DBD::XXXXX;

I don't like the column types that Interchange defines!

I change the ASCII file, but the table is not updated. Why?

Why do I even need an ASCII file?

            Database products products.txt dbi:mysql:test_minivend
            Database pricing pricing.txt dbi:mysql:test_minivend

Interchange overwrites my predefined table!

59.2. How can I use Interchange with Microsoft Access?

Though Interchange has ODBC capability, the Microsoft Access ODBC driver is not a network driver. You cannot access it on a PC from your ISP or UNIX system.

However, you can turn it around. Once you have created a MySQL or other SQL database on the UNIX machine, you may then obtain the Windows ODBC driver for the database (MySQL has a package called myODBC) and use the UNIX database as a data source for your PC-based database program.

Here is a quick procedure that might get you started:

            http://www.mysql.com/
            http://www.mysql.com/rpm/
            mysqladmin shutdown
            safe_mysqld --skip-grant-tables &
            mysqladmin create test_odbc
            mysql test_odbc
            mysql> create table test_me ( code char(20), testdata char(20) );
            Query OK, 0 rows affected (0.29 sec)
        
            mysql> insert into test_me VALUES ('key1', 'data1');
            Query OK, 1 rows affected (0.00 sec)
        
            mysql> insert into test_me VALUES ('key2', 'data2');
            Query OK, 1 rows affected (0.00 sec)
        
            mysql>
            http://www.mysql.com/

Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Frequently Asked Questions

60. How does Interchange work?

60.1. Where are the pages?

Interchange pages are not kept in normal HTML space. Look in the catalog subdirectory pages. The pages are always filtered through the Interchange daemon before being delivered.

60.2. Where are the images?

Interchange is a CGI program, and if relative image paths are used, IMG tags like the following will occur:

<IMG SRC="/cgi-bin/simple/../whatever.jpg">

Interchange, by default, uses an ImageDir for a prefix. In the demo, image specs that have no absolute path information are prefixed with /simple/images/.

In an Interchange page, this tag:

       <IMG SRC="ordernow.gif">

will become this:

       <IMG SRC="/simple/images/ordernow.gif">

This tag:

       <IMG SRC="items/00-0011.jpg">

will become this:

       <IMG SRC="/simple/images/items/00-0011.jpg">

Absolute image paths are not affected. An image such as /other/images/whatever.gif will not be changed.

61. INSTALLATION

61.1. Configuration Problems

Most Interchange configuration and setup problems are due to one of the following:

Wrong information given to makecat program.

Too-low version of Perl.

Perl compiled with USE_THREADS.

If you are setting Interchange up for the entire machine, and not just as a virtual host user, it is usual to create a special interch user to run the daemon and the link program. This means the directory listing for your cgi-bin should be something like:

-rwsr-xr-x   1 interchange users        6312 Dec 30 11:39 cgi-bin/simple

and for the socket file it should be:

srw-------   1 interchange users           0 Dec 30 11:41 etc/socket

Once you have set up the software, you can easily install catalogs as root as long as your umask is set to 2 or 22.

(The following assumes you have made the Interchange software owned and run by the special user interchange and that each user has a Interchange catalogs directory /home/user/catalogs).

The best way to set permissions on a multi-user system is to make all files group readable and writable (660 or 664 mode). If you have a system setup that places each user in their own group, make interchange a member of each user's group and set ownership and permissions with:

       find /home/user/catalogs -print | xargs chown user
       find /home/user/catalogs -print | xargs chgrp user
       find /home/user/catalogs -print | xargs chmod g+rw

For best results, set the user's default umask to 2, so that they will, by default, create files that have the proper permissions. If you have all users in the same group, the above is not secure. You should put interchange in a group of which no user is a member (perhaps interchange would be a good choice) and set all files owned by the group interchange and all directories to mode 2770:

This will make files default to the proper group when created (on most UNIX versions, anyway).

       find /home/user/catalogs -print | xargs chown user
       find /home/user/catalogs -print | xargs chgrp interchange
       find /home/user/catalogs -print | xargs chmod g+rw
       find /home/user/catalogs -type d -print | xargs chmod g+s

If you are on a virtual hosting system, the procedure varies. Making the program setuid should work for most systems. If your setup uses CGI-WRAP or another setuid scheme, it should still work. However, you may have to unset the setuid bit with chmod u-s cgi-bin/simple or the like. If you have a non-standard CGI setup, as some virtual host systems do, you will need to know something about UNIX and the web or engage a consultant to properly set up the paths. Usually switching to TLINK/INET mode is the easiest thing to do, though with Iserver and a few others it may take more than that.

If you used the makecat program to build the catalog, it should have warned you if it was not able to make the link program setuid. To set the program (in the file cgi-bin/simple in this example) to be setuid, use the command:

   chmod u+s cgi-bin/simple

61.2. Error -- the Interchange server was not running...

This indicates that the link CGI is not communicating with the Interchange server. Important note: The server should always be started by the same user ID which owns the suid vlink program. (This does not apply to TLINK/INET mode.)

The server must be running, first of all. If you didn't start it, you can do so by going to the Interchange home directory and typing:

   bin/interchange -restart

You can check to see if your server is running by typing:

   Linux, BSD:           ps -ax | grep interchange
   Most other systems:   ps -elf | grep interchange


Note: Solaris and IRIX truncate the string, and don't allow setting of the $0 parameter. You may have to grep for 'perl' instead.

If the server is not running, it may have failed due to another process occupying the TCP socket 7786. If using VLINK, try starting Interchange with start -u, which will not monitor the internet-domain socket.

If VLINK is not communicating with the server, there are a number of possible reasons. First, if you are trying to run Interchange on an ISP, go to the section about ISP problems. It is probably one of those. If you are running Interchange on a single machine, it is probably one of:

   1. Permissions problems
   2. Interchange on NFS-mounted file system

Check the error_log file for your HTTP server -- it will almost always tell you what the problem is, unless there is a simple permissions problem.

Permissions are easy. If starting Interchange like this works:

        interchange -r SocketPerms=666

then you have a socket permission problem. Try restarting interchange without the above adjustment of SocketPerms=666, and then try accessing it again with each of these mode changes:

        chmod u+s cgi-bin/storename
        chmod u-s cgi-bin/storename

           cgi-bin/storename = path to your executable

If neither of those work, either the UID the program is owned by is wrong, or your HTTP server is interfering in some fashion. If you are running Interchange on an NFS-mounted file system, it cannot run in server mode because UNIX-domain sockets don't work on NFS. You will need to change to static mode from server mode, or better yet, put Interchange on a file system that is directly mounted.

You can use Interchange in INET mode along with the tlink.c program to allow running across NFS boundaries. If you have not changed the configured defaults, and still it will not communicate, you should try setting the LINK_HOST and LINK_PORT directives in tlink.c and recompiling.

61.3. I get messages like 'Config.pm not found.' What does it mean?

This means your Perl is not properly installed, or that Interchange is not using the proper Perl binary. On UNIX, try reinstalling Interchange and using the standard Perl installation sequence:

   /complete/path/to/proper/perl Makefile.PL
   make
   make test
   make install

Otherwise, contact your system administrator.

61.4. Can't locate lib.pm in @INC. BEGIN failed--compilation aborted.

Again, your Perl is not properly installed. Someone has put a Perl up on your system, then either moved or removed the library directory. Contact your system administrator and request that Perl be re-installed.

61.5. Segmentation fault or other core dump.

If this happens when you run the Interchange test or server, it is always Perl that has a problem. Not sometimes, always. A proper Perl should never have a segmentation violation, period. And it should not dump core (unless you passed it a -u option somehow).

You will need to either update Perl or report the bug to the proper personnel. Depending on your situation and technical ability, this may be your system admin, ISP, or the Perl porters.

61.6. Configuring catalog whatever...Use of uninitialized value at Config.pm line 1614, <CONFIG> chunk 322.

This is a warning from Perl indicating that an empty value was found where one is expected. The warning is left in so that you know that something is missing. Whatever it is, it can be found at the specified "chunk," or line, of catalog.cfg. If you use the include capability, it would have to be factored in as well.

The usual reason is that a file is specified in one of the directives (usually one of Help, SearchProfile, OrderProfile, Buttonbars, or UpsZoneFile) and does not exist. See the documentation for the directive on how the file name should be specified.

61.7. Why isn't the above error more enlightening?

Because Perl won't tell us what exactly went wrong. See its FAQ for why.

61.8. XXXXXX.pm does not match executable version.

This is a Perl which does not have the right Perl library installed. It usually results from a naive system administrator who thinks they can bypass the 'make install' for Perl and just copy the Perl binary or directories.

If you installed Bundle::Interchange locally in your Interchange directory, it may mean that your system administrator updated Perl and failed to select the binary compatibility option.

61.9. Can I run Interchange on the Macintosh or Windows?

Interchange will not run on a MacOS 7, 8, or 9 operating system. It will run on Mac OS X and other PowerPC Unix variants.

Interchange's *files* can be manipulated by any computer. As long as uploads/downloads of database source, pages, and configuration files are done in ASCII mode, there is no reason why they can't be edited on a Mac. And with MySQL or other ODBC databases on your UNIX-based ISP, you can even directly interface to the database you use with Interchange provided you have the scarce ODBC middleware needed for the Mac.

Interchange can be run on Windows with the Cygwin tool set (1.3.2 or higher) available from http://www.cygwin.com/, but there are numerous anomalies and it may be difficult to get operating reliably. It is never recommended that you run a production catalog on a Windows system; if you do get it working you should only use for catalog development.

61.10. Error -- 'make: command not found'

The error is caused when the system you are installing on does not have the program called "make". It is recommended that you install make as well as a C compiler ("cc" or "gcc") for the installation of Interchange. If you are unsure of how to do this for your operating system, it may help to ask a mailing list related to your operating system.

61.11. Templates aren't showing, only the center content of the page itself

Example question: "All that's showing up is the center section of the template. This happened after ____: (moving my site to a new host, or uploading a new catalog.cfg or theme.cfg file, or restarting interchange)."

This can happen if:

From unix, do an octal dump on some of the files to see if you have cr chars:

od -a templates/foundation/theme.cfg | grep cr
od -a catalog.cfg | grep cr

If something appears on the screen, then your file needs to be cleaned. Among the other 10-million ways to clean it, here is one:

perl -pi -e 's/\r\n/\n/g' < old_file.cfg > new_file.cfg

Also, if you are using FTP to transfer the files from a Windows machine, try using ASCII mode instead of binary mode.

61.12. When I try to install the RPM, I get "failed dependencies" errors

There are two easy solutions to this problem:

perl -MCPAN -e "install Bundle::Interchange"

62. SSL problems

62.1. Shopping cart is dropped when using SSL.

If you are using a separate secure and non-secure domain, this is due to the cookies from the user not matching as well as the session ID not being able to be transferred due to differing source IP addresses.

This is sometimes due to the HostnameLookups (Stronghold/Apache parameter) not matching for the two servers, secure and non-secure. It can also be caused by the user having different web proxy addresses for HTTP and HTTPS. If it still does not work, try changing some of the appropriate configuration parameters in interchange.cfg:

   DomainTail   No
   IpHead       Yes

If you still are having problems, try this combination in catalog.cfg, the catalog configuration file:

   SessionExpire  10 minutes
   WideOpen       Yes

The above setting will typically make Interchange work when it is possible to work. Sometimes when you have multiple Interchange servers sharing the same secure server, you will have problems after accessing the second one. (The first one issues a session ID cookie, and that causes problems).

62.2. I have a different secure server domain. Why does the shopping cart get dropped?

First of all, it is questionable business practice to not certify your secure server. Besides violating the terms of use of many certificate issuers, customers notice the changed domain and it is proven by user surveys and long experience that you will receive fewer orders as a result. Certs can be obtained for $125 US per year, less than the typical cost of one hour of a top consultant's time. Do your business a favor -- spend the money to get a cert.

If you insist on doing it anyway, probably driven by the fact that you need a dedicated IP address for a secure server, you can use the solutions in the previous FAQ question and get some relief.

But by far the best way is to have all orders and shopping cart calls go only to the secure domain. Your users may get a different session when browsing the non-secure catalog pages, but it will matter little.

To do this on the Foundation demo, place in catalog.cfg:

AlwaysSecure order ord/basket ord/checkout

A more complete list might be:

AlwaysSecure <<EOF
         account
         change_password
         customerservice
         login
         logout
         new_account
         ord/basket
         ord/checkout
         order
         process
         query/check_orders
         query/order_detail
         query/order_return
         returns
         saved_carts
         ship_addresses
EOF

Add pages of your own that need to be sure of coherent session information.

For all *forms* to be secure, make sure "process" is on that list. (Your search forms will still be non-secure if you use "[process-search]" to produce the form ACTION.)

To make individual order links secure, use this instead of "[order]":

<A HREF="[area href=order secure=1 form='mv_order_item=SKU_OF_ITEM' ]">Order it</A>

To make a form-based order button secure, use "[process secure=1]" as the ACTION.

62.3. My images aren't there on the secure server!!!

You have a different document root, or the permissions are not such that you can access them. You can set a different base URL for images with:

        ImageDirSecure   https://your.secure.server/somewhere/images

Don't try to set it to an http:// URL -- images will be broken anyway.

62.4. My secure pages fail when the browser is MSIE.

MSIE has several SSL bugs, particularly in V5.01. See the Apache-SSL or mod_ssl FAQ. You can sometimes fix this with an httpd.conf change:

SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown

63. ISP Problems

The great majority of ISPs provide some CGI service, and more and more run systems that are compatible with Interchange. The new catalog configurator for Interchange makes setup much easier. A word of warning: if you chose your ISP mostly on price, you can expect problems. The low-cost providers typically have heavily-loaded machines and many domains. The more domains and the more load the unhappier you will be with Interchange. Interchange works best on a fast machine with plenty of memory.

A few Internet Service Provider (ISP) systems still have difficulty with one or the other aspect of running Interchange. A few cannot (or will not) run Interchange at all. On top of that, many times ISP personnel are too busy to help, won't help, or don't know enough to help. Some are secretive about details of the setup of their systems.

All in all, you can have a fair amount of confidence that your ISP can run Interchange. Or, you can get one who will. 8-)

63.1. No shell access allowed on my ISP.

Generally it is a waste of time to try to use Interchange without shell access.

63.2. We're sorry, the Interchange server is unavailable...

(The following assumes that you were able to start the Interchange server.)

This could be almost anything, but with a properly configured Interchange it is almost undoubtedly due to your cgi-bin and/or your Interchange directory being located on a different filesystem than the actua machine that is executing the program. VLINK uses UNIX-domain sockets, which don't work on NFS-mounted filesystems.

Iserver.com and other systems which use chroot HTTP servers require quite a bit of extra configuration to get going. If you have not been careful to set permissions properly when running in VLINK/UNIX mode, the link CGI will not be able to communicate with the Interchange server. Please read the documentation that covers this in detail.

You can run in INET mode with the tlink link program to prevent those problems.

63.3. Document contains no data or premature end of script headers (especially on BSDI or FreeBSD).

This usually means that your HTTP server ran out of resources during the execution of the link program. It couldn't create more sockets, is unable to create a process, or can't open any more files.

This usually happens in frames catalogs, when Interchange is sending more than one page simultaneously. And even more especially on FreeBSD and BSDI, which are often distributed with the kernel parameters SOMAXCONN and CHILD_MAX set to levels unsuitable for serving the web.

Go to <http://www.deja.com> and try searching for MAXUSERS. This should give you plenty of pointers on how to set these parameters properly.

63.4. Interchange server only runs for a while, then dies.

Many ISPs don't allow your user ID to run a program unless it is logged in! The moment a watchdog program notices a daemon running with a non-logged-in UID, it terminates the program. Or, it terminates programs that haven't been active for XX minutes. Contact your ISP about this. They may be able to do something for you.

63.5. My entire home directory is in HTML document space.

If working with an ISP where all of the files are in HTML document space, disable all access to the Interchange catalog directory with the proper HTTP access restrictions. Normally that is done by creating a .htaccess file like this:

        <Limit GET POST>
        order allow,deny
        deny from all
        </Limit>

If unable to do this, do not run Interchange unless file permissions can be set such that files will not be served. However, security will be a problem and customers' personal information could be placed at risk.

64. SYSTEM CONFIGURATION

64.1. Can I run multiple catalogs on one server?

Yes. Interchange supports multiple independent catalogs. There are users who run more than 500 catalogs on a single machine. The capacity is usually a function of how busy the catalogs are and how much memory and processor speed your system has.

64.2. How do I start Interchange when I reboot?

Use the standard facility on your operating system. For BSD-style systems, the file is usually called rc.local (in the /etc directory).

On SVR4 systems, it is quite a bit more complex. Look for the /etc/rc.d directory and see what other programs do. Often the file is called S99startup or something similar.

Important note: Interchange must not run as root, which is the user identity that the startup file executes. (Interchange will refuse to start if executed as root.) The technique to start up depends on the facility of your su(1) command. This should work on most operating systems:

   su interchange <<EOF
   /your/interchange/dir/bin/restart
   EOF

The EOF must be the only thing on the line (no leading or trailing whitespace). If your su(1) command has a -c option (as most System 5 UNIXes do), you can just set:

   su -c /your/interchange/dir/bin/restart interchange

Interchange supplies a restart script which tries to do the above portably. It works on many operating systems.

64.3. I installed the Interchange RPM, and I can't restart.

This usually means that you tried to run /usr/lib/interchange/bin/interchange, which fails to take into account the Linux Standard Base (LSB) file setup. Instead, run

/etc/rc.d/init.d/interchange restart

or

/usr/sbin/interchange -r

64.4. How do I set up a mall?

Interchange can share product databases, session files, and any other databases. It has many features which support mall building. You can easily build separate and mostly identical catalogs which you link to via HTML. But building a mall is as much an exercise in data and process as in software. Consider the following questions:

  1. Who will be clearing payment?
  2. What happens if everyone doesn't have the same tax rate?
  3. How will you clear orders to multiple vendors?
  4. How will you bring together multiple types of shipping?
  5. How will the vendors get product data (including images) to you?

If you cannot answer those questions and visualize how to build a mall, you probably should not try.

65. PRODUCT OPTIONS

65.1. Can I attach a size or color to a product?

Interchange has product modifiers, or attributes, which can be carried around with the product. Inside an item list or the product page (flypage), the [item-options] tag will automatically place suitable widgets on an HTML form, and "remember" what should be selected. See the Interchange documentation for Item Options.

You can use the SeparateItems directive or set the mv_separate_items variable on the order form to cause ordered items to be put on separate lines in the shopping basket. (This is the default in the demo catalogs.)

65.2. Can I change the price based on size or color (or other attribute)?

Yes. Use the Interchange UI to set up your product options. It operates on the options database table to set up options that can effect price. Or see the next question.

65.3. How are simple product options structured?

Interchange has three types of options; simple, matrix, and modular. They are based on the options database table.

To enable options for a product, it needs to have a master record in "options" with the SKU as the key. The only fields that matter in the master record are:

code        The SKU of the item

o_master    Indicates not a product, but an option for a product in another database

o_enable    Options enabled for that item

o_matrix    Set to 1 for all-in-one widgets, 2 for separate widgets

o_modular   Modular options (alpha)

If o_enable is set, but neither o_matrix or o_modular are, the item is using simple options.

For the option itself in simple mode, the following fields apply:

code        Arbitrary key
sku         SKU this option applies to
o_group     The attribute name of the option
o_label     The label the widget for the option will bear
o_value     The options, in IC option format
o_widget    The widget type used to display
o_height    The widget height (if any)
o_width     The widget width (if any)
price       Price adjustment

Here are the fields for an item with a simple size option:

code:os28009
o_master:1
o_enable:1
o_matrix:0
o_modular:0
#
code:os28009-size
sku:os28009
o_group:size
o_label:Size
o_value:S=Small,M=Medium,L=Large,XL=Extra Large
o_widget:select
o_height:
o_width:
price:S=-1.00,XL=1.00
#

The price field accepts option modifiers based on the option value; for example, to adjust the price of an S down 1.00 and the price of an XL up 1.00, you use the values shown above. This works in conjunction with the special ==:options atom in CommonAdjust. To activate the pricing adjustment, you must have something like this for your CommonAdjust setting:

 CommonAdjust    :sale_price, ;:price, ==:options

The actual names of the fields used for these can be changed with the Variable MV_OPTION_TABLE_MAP, i.e.

Variable MV_OPTION_TABLE_MAP <<EOM
        o_widget  widget
        o_value   value
EOM

That would allow you to use "widget" and "value" in place of o_widget and o_value as field names.

65.4. But what do these options do? Where do they live?

If you know Perl, you know what a hash reference is. An Interchange shopping cart consists of an array of hash references. If you dump the structure of the main shopping cart you would see something like:

        [
        {
            mv_ip       => '0',
            price_group => 'general',
            mv_ib       => 'products',
            code        => 'os28080',
            quantity    => '1',
        },
        {
            mv_ip       => '1',
            price_group => 'general',
            mv_ib       => 'products',
            code        => 'os28080',
            size        => 'L',
            color       => 'black',
            quantity    => '1',
        },
     ]

Each key of the hash is an attribute. There are a number of special attributes:

Attribute Description
code The item SKU
sku The SKU of the base item (in the case of matrix options)
mv_ip The line number of the shopping cart (minus 1)
mv_ib The database table the product was ordered from
quantity The number on order
group The order group for a master item or subitem
mv_si Subitem indicator
mv_mi Master item code
mv_mp Modular item
mv_price Price of the item (to directly set pricing)
mv_order_route Special order route for this item

Any attribute besides the above is a product option or modifier, and can be displayed with [item-modifier attribute_name].

66. ENCRYPTION

66.1. PGP encryption -- Server Error

As always, check the error log. The most common problem is something like:

   akopia.com 3Ex5lvta:akopia.com - [01/Sep/1997:09:08:43] simple /cgi-bin/simple
   > Encryption error:
   >

Also, check the ScratchDir (usually tmp/) for .err files; they will contain PGP or GPG's error output.

Probable causes:

Interchange user ID doesn't have keyring

EncryptProgram directive set wrong

66.2. PGP encryption -- What do I do now that it is working?

This depends on what you do with orders once you receive them by email. Some PC mail agents (notably Eudora) will decrypt the PGP message embedded within the message text. In that case, you can simply embed the [value mv_credit_card_info] call right in the message and be done with it.

If your mailer will not decrypt on the fly, the best way to read the credit card number is to set up MIME encoding of the order email. To do this, find the order report you are using. In the standard demos it is pages/ord/report.html or etc/report.

Set up two MIME regions in that file. First, at the top of the file:

   [tag mime type TEXT/PLAIN; CHARSET=US-ASCII][/tag]
   [tag mime Order Text]

   ORDER DATE: [calc]localtime[/calc]
   ORDER NUMBER: [value mv_order_number]

   Name: [value name]
   Company: [value company]

   (Rest of order text, including item list)
   [/tag]

Then, at the bottom of the report.html file, put the credit card info:

   [if value mv_credit_card_info]
   [tag mime type application/pgp-encrypted][/tag]
   [tag mime Credit Card Information]

   [value mv_credit_card_info]

   [/tag]
   [/if]

Once this is done, you can read mail using your PGP client as a helper application to decode the MIME attachment. This does not require a fancy setup -- you can use the standard MIT PGP 2.6.2 if desired. If you are using UNIX, set up as the helper for the MIME type application/pgp-encrypted:

   xterm -e pgp -m %s

More automated or user-friendly setups are left as an exercise for the user.

67. How do I....

67.1. How do I get the number of items in a shopping cart?

If it is simply the total number, extended according to quantity, you can use the [nitems] tag. If you need this number for use in an embedded Perl script, you can use:

   $number = $Tag->nitems();

If it is the number of line items you need, then you can use a Perl script:

   [perl]
       return scalar @{$Carts->{main}};
   [/perl]

(The 'main' refers to the main shopping cart.)

If you have SeparateItems in effect, and need the number of unique items, you could use:

   [perl]
       my $cart = $Carts->{main};
       foreach my $item (@$cart) {
   @items = split /\|/, $items;
   $count = 0;
   for (@items) {
   $count++ unless $seen{$_}++;
   }
   $count;
   [/perl]

67.2. How do I delete an item from the cart in Perl?

(Answered by Racke)

[calc] @$Items = grep {$_->{code} ne '123.456.789'} @$Items [/calc]

67.3. The demo doesn't do ... (pick one)

That is because it is a demo. It is not intended to be a finished catalog, just a starting point.

That being said, you should think long and hard before abandoning the checkout schema. Years of experience have led to the production of the userdb, transactions, and orderline tables, and the structure of the checkout page. Any changes to the data structure should be thoroughly tested before deployment, as obscure errors can cause major problems in order logging.

67.4. How can I trace the source of a purchase and run a partners program?

Interchange has a facility that adds a parameter called source to the session database for that user. You should give your partners a source code, which must contain at least one letter character (A-Za-z only). It is placed in the sourcing URL as a query string of:

   mv_pc=Source1

If this is appended to the URL with which the user calls Interchange, it will then be placed in the session identifier source.

This URL:

http://yourcatalog.com/cgi-in/yourcat/sp_offer?mv_pc=Source1

will yield Source1 from the Interchange tag [data session source].

The Minivend 3 idiom ?;;Source1 continues to be supported, so existing partner sites should work without change.

67.5. How can I send an email copy of the receipt to a user?

There are several ways, but this is a more complex question than it may seem like it is. You will have to deal with bad email addresses, deciding which information to send, showing delivery times, etc. You also have to be very careful with credit card information. If you have not taken the proper security measures (by enabling PGP credit card encryption or using CyberCash), you might just mail them their own unencrypted credit card number!

This is supported in Interchange via a UserTag, [email ...]. See the "simple" and "basic" demos.

67.6. How do I display Euro pricing?

You can use Interchange's II8N facilty via the Locale directive. In catalog.cfg:

# to define the euro-Settings (PriceDivide is for converting from DM)
Locale eur_EUR PriceDivide         1.95583
Locale eur_EUR p_cs_precedes       0
# this is great - you can even use HTML-Tags to display an euro-image
Locale eur_EUR currency_symbol     "<IMG src="/path/to/image/euro.gif">"
Locale eur_EUR p_sep_by_space      2
Locale eur_EUR mon_decimal_point   ,

# and the DM
Locale de_DE
Locale de_DE p_cs_precedes  0
Locale de_DE p_sep_by_space 2


Note: Be sure to use the latest exchange rates when you establish your catalog.

On your pages (this is from a search results page, the [item-.... ...] notation may be different depending on your context):

[item-price]<br><!-- german is default -->
[setlocale eur_EUR]
  [currency convert=1][item-field price][/currency]<br><!-- the euro -->
[setlocale]

Any questions? Read the docs about "Internationalization."

67.7. How do I empty the shopping cart?

Here are three examples of ways to empty/drop/clear the shopping cart contents.

67.7.1. Empty shopping cart

[calc]
        @{$Carts->{$CGI->{mv_cartname} || 'main'}} = ();
[/calc]

67.7.2. Empty shopping cart

[set clear_basket]
        [calc]
                @{$Carts->{$CGI->{mv_cartname} || 'main'}} = ();
        [/calc]
[/set]

[button
        text="Clear Basket"
        src="clear_basket.gif"
        hidetext=1
        form=basket
        ]
                mv_todo=refresh
                mv_click=clear_basket
[/button]

67.7.3. Erase the user session (includes shopping cart)

[button
        text="Clear Basket"
        src="clear_basket.gif"
        hidetext=1
        form=basket
        ]
                mv_todo=cancel
                mv_nextpage=index
[/button]

67.8. How do I e-mail credit card numbers in plain text?

(Answered by Mike Heins)

The position of ICDEVGROUP is that we will not tell you what you can and cannot do, but that we simply will not help you send unencrypted CC numbers by email.

67.9. How do I setup multiple shipping addresses?

Interchange has the facility to handle multiple addresses. See the User Database Functions section of the Interchange Database manual.

67.10. How do I change the order number from TEST0001, TEST0002 to something else?

(Answered by Aaron Hazelton & Paul Jordan)

67.11. How do I move a catalog from a test server to a production server?

(Answered by Jonathan Clark)

1) copy the complete catalog root with all files and subfolders.

2) make sure the permissions are appropriate (interchange daemon user needs rw access to all of it.

3) link <catroot>/error.log to /var/logs/interchange/catalog/error.log or wherever.

4) link catroot/images to images folder in your public html space.

5) link the admin ui images folder 'interchange' in public html space to actual location.

6) copy any global usertags which are not in your catalog structure.

7) edit the variable.txt to set appropriate domain names if these have changed.

8) if using MySQL/Postgres/Oracle, set up database access.

9) put a link program in your cgi-bin, make sure it is chmod u+s and owned by the interchange daemon user.

10) add the catalog to the interchange.cfg file.

11) restart ic.

12) check global error.log for any error messages.

67.12. How do I access the raw match count?

(Answered by Kevin Walsh)

[value mv_search_match_count]

67.13. How do I add the thumbnail to the results page?

(Answered by Ed LaFrance & Dan Browning)

It's as easy as <img src="thumb/[item-field thumb]">, but you may want to add a check to see if the image is actually there before you try to display it:

[if file images/thumb/[item-field thumb]]
        <img src="thumb/[item-field thumb]">
[/if]

For example:

--- results.html.orig   Sat Jun 29 21:25:49 2002
+++ results.html        Sat Jun 29 21:28:57 2002
@@ -100,6 +100,7 @@

 <table width="90%" border="0" cellspacing="0" cellpadding="3">
 <tr class="contentbar2">
+  <td>&nbsp;</td>
   <td><b>&nbsp;Product</b></td>
   <td align="center"><b>SK/b</td>
   <td align="center"><b>Stock</b></td>
@@ -120,6 +121,11 @@

 <tr valign="middle">
       <td>
+                  [if file images/thumb/[item-field thumb]]
+                     <img src="thumb/[item-field thumb]">
+                  [/if]
+      </td>
+      <td>
        <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="[item-code]">
        <a href="[area [item-code]]">[item-description]</a>
       </td>

67.14. How do I do a random display of items?

(Answered by Bill Carr)

If you are using mysql (and others probably), you should be able to add "ORDER BY RAND()" to your SQL query. For example:

[query
   list=1
   sql=|SELECT * FROM products ORDER BY RAND() LIMIT 3|
]
[list]
        [sql-param description]<br>
[/list]
[/query]

67.15. How do I setup a new real time payment processor that isn't yet supported by Interchange?

If the payment processor that you would like to use isn't supported by Interchange out of the box, then a new payment module would need to be developed for that processor before you could use them.

If you are up to the task of programming a new payment processor module yourself, the ICDEVGROUP would be happy to add your contribution to the growing list of Interchange-supported payment processors. Feel free to take a look at the lib/Vend/Payment directory to see examples of current payment modules.

If developing the module on your own isn't an option, you may engage a competent Interchange developer to do it for you or use one of the already-supported payment modules.

67.16. How do I modify orders after they are placed, change items, shipping, etc.?

Example question: "Occasionally, I need to modify orders... Add an Item, Change shipping, etc. What is the best way or how can it be done?"

The Foundation template does not have this functionality "out of the box". While one can manually modify the tables via the Admin UI, it would not cause IC to automatically recalculate subtotals, tax, shipping, etc. to account for the modifications.

Until someone gets the "itch" to program that feature into the Admin UI, some users are solving the problem by handling all of these modifications in a Back Office / Accounting / ERP software system. For example, IC comes with "out of the box" support for integration with Quickbooks. At that point, however, it becomes necessary to analyze what (if any) syncronization will be performed between the two systems.

67.17. How do I make or get a certificate for SSL?

This is handled separately and independantly from Interchange, and there are lots of documentation on buying and installing certificates for your platform and http server, as well as generating certificate signing requests (CSR). Companies such as GeoTrust and Thawte sell certificates, and often have some documentation on what the process entails. The Apache, mod_ssl, and OpenSSL user groups may be of assistance as well.

While it is technically feasible to generate your own self-signed certificate, modern browsers will display a warning if the certificate is not signed by a signing authority known to that browser.

67.18. How do I perform multi-table SQL queries and/or joins using dot notation?

(Answered by Mike Heins)

Example question: "How come I can't use [sql-param tablename.fieldname] notation when I do a multi-table query?"

DBI simply does not support tablename.fieldname in the return value.

You can just refer to them by the fieldname. In the case of field names that are the same but need to be selected from different tables, you can use "SELECT orderline.quantity as o_quan,..." and refer to it as [sql-param o_quan].

67.19. How do I modify the Save Cart and Recurring Cart feature? How do they work?

The code for these features is in templates/components/cart. The relative portion that is executed first when you call the basket page is this:

      [button
          text="Save This Cart"
          src="__THEME__/savecart.gif"
          extra="class=contentbar2"
          hidetext=1
          form=basket
          mv_check="Save This Cart"
      ]
          mv_todo=return
          mv_nextpage=ord/basket
          save_cart=cart
      [/button]
      [button
          text="Set As Recurring Order"
          src="__THEME__/saverecur.gif"
          extra="class=contentbar2"
          hidetext=1
          form=basket
          mv_check="Set As Recurring Order"
      ]
          [set save_cart]recurring[/set]
          mv_todo=return
          mv_nextpage=ord/basket
          save_cart=recurring
      [/button]

This creates two buttons that set save_cart to either 'cart' or 'recurring', then go to the ord/basket page (where you are already). When clicked, one of these two code blocks will be executed:

 [if value save_cart eq 'recurring']
            <FORM ACTION="[process-target]" METHOD=POST>
            To save this recurring order, give it a nickname, then press 'Save Cart'.<br>
            Nickname:
            <INPUT TYPE=TEXT NAME="c_nickname" SIZE=11 VALUE="[scratch just_nickname]">
            <input type=hidden name=mv_session_id value="[data session id]">
                        <INPUT TYPE=HIDDEN NAME="c_recurring" VALUE="1">
            <INPUT TYPE=HIDDEN NAME="save_cart" VALUE="recurring">
            <INPUT TYPE=HIDDEN NAME="mv_todo" VALUE="return">
            <INPUT TYPE=HIDDEN NAME="mv_check" VALUE="Save Cart">
            <INPUT TYPE=SUBMIT VALUE="Save Cart">
            </FORM>
  [elsif value save_cart eq 'cart']
            <FORM ACTION="[process-target]" METHOD=POST>
            To save this cart, give it a nickname, then press 'Save Cart'.<br>
            Nickname:
            <INPUT TYPE=TEXT NAME="c_nickname" SIZE=11 VALUE="[scratch just_nickname]">
            <INPUT TYPE=HIDDEN NAME="c_recurring" VALUE="0">
            <INPUT TYPE=HIDDEN NAME="save_cart" VALUE="cart">
            <INPUT TYPE=HIDDEN NAME="mv_todo" VALUE="return">
            <INPUT TYPE=HIDDEN NAME="mv_check" VALUE="Save Cart">
                        <input type=hidden name=mv_session_id vlaue="[data session id]">
            <INPUT TYPE=SUBMIT VALUE="Save Cart">
            </FORM>
  [/elsif]

The "nickname" for the cart is set earlier via:

[if !scratch just_nickname]
  [seti just_nickname][tag time]%b-%d-%Y[/tag][/seti]
[/if]

The real work is done because of this: <INPUT TYPE=HIDDEN NAME="mv_check" VALUE="Save Cart"> which calls the following code after the the user clicks "Save Cart":

  [set Save Cart]
   mv_todo=return
   mv_nextpage=ord/basket
   save_cart=none
   [save_cart nickname="[value c_nickname]" recurring="[value c_recurring]"]
  [/set]

Which in turn calls the usertag "save_cart" with a nickname parameter and a recurring parameter. Depending on which button was clicked, recurring will either be 0 (for "Save This Cart") or 1 (for "Set As Recurring Order"). The save_cart usertag adds the cart to the userdb.carts field as a Perl data structure (hashes, arrays, etc.).

68. Errors

68.1. Sorting doesn't work across multiple pages.

If you are using the [sort table:field] idiom, it cannot. It sorts data present in the list only.

68.2. I am searching for a string and it is not found. I know it is there!

Set mv_substring_match to yes (su=yes in one-clicks). This most commonly happens when searching for non-ISO-8859 (Cyrillic, or characters like umlaut and eacute) characters in word-match mode. The problem is, that unless your locale is set up properly, Perl doesn't think a non-ISO-8859 and a space character is a boundary.

Also, if you are searching for non-alpha characters, they will also not be interpreted as word characters and the boundary problems will still exist.

69. Performance Issues

Interchange is not a lightweight program. If you are running it on a low-end ISP, whose major selling point is low cost, you will frequently find that Interchange performance is very poor. This is due to either:

Not enough memory

Too many domains

Underpowered machine

69.1. Interchange runs, but it's sooo sllooowww...

This is almost certainly due to a system that has inadequate memory or network bandwidth. On a moderately fast ISP server with sufficient memory, pages should start displaying in less than 2 seconds. On a fast server, pages should start loading almost instantaneously.

69.2. Interchange slows down over time.

There are many possible reasons for this, but most have to do with memory or session database size.

69.3. I am using SQL, and Interchange is slow ...

It isn't Interchange. First of all, did you index your 'SKU' or other key fields? The reason Interchange doesn't do it for you is that every SQL database seems to do that a bit differently. Even then, you can try Interchange's COLUMN_DEF parameter:

Database products COLUMN_DEF code=char(16) PRIMARY KEY

This will at least index the code field for MySQL. Other databases differ.

Interchange can return VERY fast SQL search results. But you need to at least give it something to work with. The proper method for fast selection is:

[query sql="select code,category,title,price from products" ]

Category: [sql-param category]<BR>
Title:    <A HREF="[area [sql-code]]"> [sql-param title] </A><BR>
Price:    <A HREF="[area order [sql-param 0]]"> [sql-param price] </A><BR>

[/sql]

This is especially powerful when you consider a joined query like:

       SELECT code, price, title, extended.desc
       FROM   products, extended
       WHERE  products.category = 'Renaissance'

Note that the extended.desc field will be accessed as [sql-param desc]. Don't forget that you must index your fields if you want fast searching with them as a criteria.

70. Using Interchange with Apache and SUEXEC

Apache with SUEXEC: VLINK/UNIX socket mode will not work well unless installed as a normal user. If supporting multiple users, the TLINK/INET mode must be used.

71. A friendly reminder

When in doubt, restart the server. It won't take but a few seconds, and changes in configurable options don't take effect until it is done. You may even change a page and not see the effect until the server is restarted.

72. Tips and tricks

These are slightly edited postings to the Interchange-users mail list made by Mike Heins, lead author of Interchange.

72.1. Locking down your system

Interchange has lots of built-in protections to make developing your catalogs pretty care-free. But it will definitely pass you the ammo to shoot yourself in the foot, as will any templating system that has power. So you have to be careful, as you do in any scripting environment.

Most of the protections have to do with:

  1. Tags like [cgi foo], [data ...] and such are not reparsed for tags.
  2. The [value foo] tag never allows a left square bracket to be output.
  3. Safe is used for Perl, which means that arbitrary perl code which reads/writes or uses IO is not possible.
  4. The Interchange files don't need to be readable or writable by any other user ID, so CGI/PHP programs run by the web server can't get at them.
  5. Dangerous operations are allowed only via global UserTag, and not by catalog UserTag.

But there are ways that user-entered data could end up getting parsed for tags. The most common breach is to take possibly tainted user data entered into a form and put it in a database without filtering it first. There are several ways to do that:

        Filter  name     textarea_put
        Filter  address  textarea_put
        Filter  comments textarea_put
        Filter  email    textarea_put

There are other ways to nail down your system and make it more difficult to have a security problem.

      Database products WRITE_CONTROL 1

All in all, Interchange has been proven to be securable over time. But we all have to do our part and think about what we are doing with user-entered data.

72.2. Optimizing lists

Interchange has powerful search capabilities that allow you to produce lists of items for use in category lists, product lists, indexes, and other navigation tools.

These are a two-edged sword, though. Lists of hundreds or thousands of entries can be returned, and techniques that work well displaying only a few items may slow to a crawl when a large list is returned.

In general, when you are returning one item (i.e. a flypage) or a small list (i.e. a shopping cart) you can be pretty carefree in your use of [if ...] and [calc] and [perl] tags. When there are hundreds of items, though, you cannot; each complex test or embedded Perl snippet causes the Safe module to have to evaluate code, and each ITL tag requires parsing and argument building.

The Safe module is pretty fast considering what it does, but it can only generate a few thousand instances per second even on a fast system. And the ITL tag parser can likewise only parse thousands of tags per CPU second.

What to do? You want to provide complex conditional tests but you don't want your system to slow to a crawl. Luckily, there are techniques which can speed up complex lists by orders of magnitude.

72.2.1. Benchmarking

A non-precise benchmark of different iteration options can be done with the following global UserTag. Place this in a file in the usertag/ directory in the Interchange root:

UserTag benchmark Order start display
UserTag benchmark AddAttr
UserTag benchmark Routine <<EOR
my $bench_start;
my @bench_times;
sub {
    my ($start, $display, $opt) = @_;
    my @times = times();
    if($start or ! defined $bench_start) {
        $bench_start = 0;
        @bench_times = @times;
        for(@bench_times) {
            $bench_start += $_;
        }
    }
    my $current_total;
    if($display or ! $start) {
        for(@times) {
            $current_total += $_;
        }
        unless ($start) {
            $current_total = sprintf '%.3f', $current_total - $bench_start;
            for(my $i = 0; $i < 4; $i++) {
                $times[$i] = sprintf '%.3f', $times[$i] - $bench_times[$i];
            }
        }
        return $current_total if ! $opt->{verbose};
        return  "total=$current_total user=$times[0] sys=$times[1] " .
                "cuser=$times[2] csys=$times[3]";
    }
    return;
}
EOR

Then at the beginning of the code to check, call

        [benchmark start=1]

to start the measurement. At the end

        [benchmark]

will display the time used. Bear in mind that it is not precise, and that there may be variation due to system conditions. Also, the longer the times and the bigger the list, the better the comparison.

To see the system/user breakdown, do:

        [benchmark verbose=1]

In general, "user" time measures Interchange processing time and and the rest are indicative of the database access overhead, which can vary widely from database to database.

72.2.2. Optimizations

    [loop prefix=foo search="ra=yes"]

        [foo-data products image]
                is slightly faster than
        [foo-field image]
                which is MUCH faster than
        [data products image [foo-code]]
                which is faster than
        [data table=products column=image key="[foo-code]"]

    [/loop]

The loop tags are interpreted by means of fast regular expression scans of the loop container text, and fetch an entire row of data in one query. The [data ...] ITL tag interpretation is delayed until after the loop is finished, whereby the ITL tag parser must find the tag, build a parameter list, then fetch the data with a separate query. If there are repeated references to the same field in the loop, the speedup can be 10x or more.

mv_return_fields (otherwise known as "rf" in one-click terminology) sets the fields that are returned from a search. Once they are returned, they can be accessed with [PREFIX-param field]. They can also be referenced with [PREFIX-pos N], where N is a digit representing the ordinal position (i.e. starting with 0) in the list of fields.

The following are equivalent:

        Benchmark loop-field list: [benchmark start=1]
        <!-- [loop search="ra=yes/st=db"]
                [loop-code] price: [loop-field price] [/loop] -->
        TIME: [benchmark]

        Benchmark loop-param list: [benchmark start=1]
        <!-- [loop search="ra=yes/st=db/rf=sku,price"]
                [loop-code] price: [loop-param price] [/loop] -->
        TIME: [benchmark]

but the second is much, much faster.

A common need when building tables is to conditionally close the table row or data containers. I see a lot of:

        [loop search="ra=yes"]
        [calc] return '<TR>' if [loop-increment] == 1; return[/calc]
        [calc] return '' if [loop-increment] % 3; return '</TR>' [/calc]
        [/loop]

Much faster, by a few orders of magnitude, is:

        [loop search="ra=yes"]
        [loop-change 1][condition]1[/condition]<TR>[/loop-change 1]
        [loop-alternate 3]</TR>[/loop-alternate]
        [/loop]

        If you think you need to close the final row by checking the
        final count, look at this:

        [loop search="ra=yes"]
        [on-match]
                <TABLE>
                <TR>
        [/on-match]

        [list]
                        <TD>[loop-code]</TD>
                [loop-alternate 3]</TR><TR>[/loop-alternate]
        [/list]

        [on-match]
                </TR>
                </TABLE>
        [/on-match]

        [no-match]
                No match, sorry.
        [/no-match]

[/loop]

This is a hundred times faster than anything you can build with multiple [calc] tags.

Consider these two snippets:

        [if scratch|value|cgi key] THEN [/if]

and:

        [if scratch|value|cgi key == '1'] THEN [/if]

The first one doesn't require Perl evaluation. It simply checks to see if the value is blank or 0, and returns true if it is anything but. Of course this requires setting your test values to blank or 0 instead of "No" or " " or somesuch, but it is anywhere from 20-35% faster.

Try it on the foundation demo:

    ---- begin test ---

    Overhead:
    [benchmark start=1]
        <!-- [loop search="ra=yes"]
                    [set cert][loop-field gift_cert][/set]
            [/loop] -->
    [benchmark]
    <P>


    if scratch compare:
    [benchmark start=1]
        <!--
        [loop search="ra=yes"]
        [set cert][loop-field gift_cert][/set]
        [loop-code] [if scratch cert] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert] YES [else] NO [/else][/if]
        [/loop]
        -->

    [benchmark]
    <P>

    if scratch compare eq 1:
    [benchmark start=1]
        <!--
        [loop search="ra=yes"]
        [set cert][loop-field gift_cert][/set]
        [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
        [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
        [/loop]
        -->
    [benchmark]
    <P>

    [page @@MV_PAGE@@]Again</a>

    ---- end test ---

You can execute the same code as [calc] with [PREFIX-calc], which has two benefits:

  1. It doesn't require ITL parsing.
  2. It is executed during the loop instead of after it.

The [PREFIX-calc] object has complete access to all normal embedded Perl objects like $Values, $Carts, $Tag, and such. If you want to make a data table (i.e. "products" or "pricing") available for access inside of it, just do:

        [perl tables="products pricing"] [/perl]

prior to list start. Now you can do something like:

    [loop search="ra=yes"]
        [loop-calc]
            $desc = $Tag->data('products', 'description', '[loop-code]');
            $link = $Tag->page('[loop-code]');
            return "$link $desc </A>";
        [/loop-calc] <BR>
    [/loop]

For repetitive routines, you can achieve a considerable savings in CPU by pre-compiling your embedded Perl code.

In the "Construct Something" demo, the bar_link() routine in catalog_before.cfg is an example of compiling the subroutine once at catalog configuration time.

You can also compile routines at the time of the list execution with [item-sub routine] CODE [/item-sub]. This means only one Safe evaluation is done -- every time the [loop-exec routine] is called, it is done fast as a call to the routine. This can be 10 times or more faster than separate [calc] calls, or 5 times faster than separate [PREFIX-calc] calls.

    [benchmark start=1]
    loop-calc:
      <!--
            [loop search="st=db/fi=country/ra=yes/ml=1000"]
            [loop-calc]
                    my $code = q{[loop-code]};
                    return "code '$code' reversed is " . reverse($code);
            [/loop-calc]
            [/loop]
      -->

    [benchmark]

    <P>

    [benchmark start=1]
    loop-sub and loop-exec:
      <!--
            [loop search="st=db/fi=country/ra=yes/ml=1000"]
            [loop-sub country_compare]
                    my $code = shift;
                    return "code '$code' reversed is " . reverse($code);
            [/loop-sub]
            [loop-exec country_compare][loop-code][/loop-exec]
            [/loop]
      -->

    [benchmark]

You can run [query arrayref=myref sql="query"], which saves the results of the search/query in a Perl reference. It is then available in $Tmp->{myref}. (Of course, "myref" can be any arbitrary name.)

This is the fastest possible method to display a list.

  --- begin test code ---
  [set waiting_for]os28004[/set]

  [benchmark start=1] Embedded Perl
  <!--
  [query arrayref=myref sql="select sku,price,description from products"]
        <!-- make query, this container text is not used. -->
  [/query]

  [perl]
    # Get the query results, has multiple fields
    my $ary = $Tmp->{myref};
    my $out = '';
    foreach $line (@$ary) {
        my ($sku, $price, $desc) = @$line;
        if($sku eq $Scratch->{waiting_for}) {
                $out .= "We were waiting for this one!!!!\n";
        }
        $out .= "sku: $sku price: $price description: $desc\n";
    }
    return $out;
  [/perl]
  -->
  TIME: [benchmark]

  [benchmark start=1] All loop
  <!--
  [query list=1 sql="select sku,price,description from products"]
        [if scratch waiting_for eq '[sql-code]']
            We were waiting for this one!!!!
        [/if]
        sku: [sql-code]
        price: [sql-param price]
        desc: [sql-param description]
  [/query]
  -->

  TIME: [benchmark]

  --- end test code ---

73. Using Interchange with Oracle

Question: should we be using the DBI ChopBlanks setting for Oracle or is Interchange trimming trailing space from CHAR fields itself?

IC daemon user should have environment variables ORACLE_HOME and possibly NLS_LANG set.

Mark Johnson (mark@endpoint.com) wrote this trigger on TABLE_NAME to update the MOD_TIME column on insert or update. The user must have been granted the RESOURCE role to create triggers. Here it is:

CREATE TRIGGER tr_modtime_for_TABLE_NAME BEFORE INSERT OR UPDATE ON TABLE_NAME FOR EACH ROW BEGIN

new.MOD_TIME := SYSDATE; END; /

74. Using Interchange with PostgreSQL

Make sure you have DBD::Pg installed and tested. Make sure POSTGRES_INCLUDE and POSTGRES_LIB environment variables are set.

75. Using Interchange with MySQL

Permissions. test_ databases usually special.

76. Using Interchange with Apache

Slightly modified article posted to the old minivend-users mail list. Minivend-users is now interchange-users.

Date: Thu, 7 Sep 2000 12:08:37 -0700
From: Bill Randle <billr@exgate.tek.com>
To: minivend-users@minivend.com
Subject: Re: [mv] no /cgi-bin/storename/

On Sep 6,  5:13am, Victor Nolton wrote:
} Subject: [mv] no /cgi-bin/storename/
} ******    message to minivend-users from Victor Nolton <ven@pragakhan.com> ******
}
} I've noticed some of the catalogs I've done are not indexed well with
} the search engine, though most pages have meta tags, there is a
} robot.txt file and so on and so forth.I assume it's due to the
} cgi-bin in the url (not sure).
}
} I'd like to start having stores be like
}
} http://www.yourdomain.com/index.html
} http://www.yourdomain.com/ord/basket.html
} instead of
} http://www.yourdomain.com/cgi-bin/yourstore/index.html
} http://www.yourdomain.com/cgi-bin/yourstore/ord/basket.html
}
} how do you accomplish this? I assume it can be done somehow.

In addition to using mod_minivend, previosuly suggested, you can do this
with Apache rewrite rules in the VirtualHost directive for yourdomain.com:

<VirtualHost a.b.c.d>
    ServerAdmin support@mainhost.com
    DocumentRoot /home/httpd/html/yourstore
    ServerName www.yourdomain.com
    ErrorLog logs/yourdomain-error_log
    CustomLog logs/yourdomain-access_log common
    ScriptAlias /cgi-bin/ "/home/httpd/cgi-bin/"
    RewriteEngine On
    RewriteRule ^$  /cgi-bin/yourstore/index.html            [PT,L]
    RewriteRule ^/$ /cgi-bin/yourstore/index.html            [PT,L]
    RewriteRule ^/index\.html$ /cgi-bin/yourstore/index.html [PT,L]
    RewriteRule ^/cgi-bin/yourstore/.* -                     [PT,L]
    RewriteRule ^/.*images/.* -                              [PT,L]
    RewriteRule ^/(.*) /cgi-bin/yourstore/$1                 [PT,L]
</VirtualHost>

I just did this for a client and it works quite well (as long as you're
using a fairly recent version of Apache as your webserver).

        -Bill

77. Perl/Interchange FAQ

77.1. Cameron Prince's local Perl installation how-to

  1. Login as user. In this example, we'll call the user bob. Bob's home directory is /home/bob.
  2. Get the perl tarball and extract it in /home/bob. (tar -xzvf perl-5.6.0.tar.gz)
  3. Create a directory for the local perl. (mkdir /home/bob/local-perl)
  4. Compile perl.
    1. cd perl-5.6.0
    2. sh Configure
    3. Choose all the defaults until you get to: "Directories to use for library searches?" Here you want to enter the new local perl path, as well as the defaults. So you should enter something like: /home/bob/local-perl/lib /usr/local/lib /lib /usr/lib
    4. Continue choosing defaults till you get to: "Any additional ld flags (NOT including libraries)?" This should be: -L/home/bob/local-perl/lib
    5. Continue choosing defaults till you get to: "Installation prefix to use? (~name ok)" This should be: /home/bob/local-perl
    6. Choose all defaults till you get to: "Directory /home/bob/local-perl/bin doesn't exist. Use that name anyway?" Enter y.
    7. Continue choosing defaults till you get to: "Do you want to install perl as /usr/bin/perl?" Enter n.
    8. Continue choosing defaults till you get to: "Directory /home/bob/local-perl/bin doesn't exist. Use that name anyway?" Enter y.
    9. Directory /home/bob/local-perl/bin doesn't exist. Use that name anyway? Enter y.
    10. Continue taking defaults till you return to a prompt.
    11. make
    12. make test
    13. make install
  5. /home/bob/local-perl/bin/perl -v
    You should see: This is perl, v5.6.0
  6. edit /home/bob/.bash_rc
    Change: PATH=$PATH:$HOME/bin
    To: PATH=/home/bob/local-perl/bin:$PATH:$HOME/bin
  7. Logout and log back in.
  8. which perl
    You should see: ~/local-perl/bin/perl or /home/bob/local-perl/bin/perl
  9. perl -MCPAN -e 'install Bundle::Interchange'
    Keep running this until you see:
MD5 is up to date.
MIME::Base64 is up to date.
URI is up to date.
Net::FTP is up to date.
MIME::Base64 is up to date.
Digest::MD5 is up to date.
HTML::Tagset is up to date.
HTML::Parser is up to date.
HTML::HeadParser is up to date.
LWP is up to date.
Term::ReadKey is up to date.
Term::ReadLine::Perl is up to date.
Business::UPS is up to date.
SQL::Statement is up to date.
Storable is up to date.
DBI is up to date.
Safe::Hole is up to date.

You may need to get the modules via ftp and install them by hand. For instance, during the test used to create this document, I had to get URI and LWP and install by hand before everything reported that it was up to date. To do this, follow these steps:

    1. ftp ftp.cpan.org
    2. cd /CPAN/modules/by-module/URI
    3. bin
    4. get URI-1.10.tar.gz
    5. quit
    6. tar -xzvf URI-1.10.tar.gz
    7. cd URI-1.10
    8. perl Makefile.pl
    9. make
    10. make test
    11. make install

Use the same basic steps for any module not properly installed by using perl -MCPAN -e 'install Bundle::Interchange'

Now, install Interchange as normal.

78. Other / Miscellaneous Questions

78.1. What does the "mv_pc" variable added to every URL mean?

It can be used to prevent the users' browser from caching dynamic content, or, combined with the session 'id', it can make every link unique so that the users behind a proxy (e.g. AOL) will not have dynamic content cached.

78.2. Where is process.html?

(Answered by Ed LaFrance & Kevin Walsh)

It is in the guts of Interchange. The [process] form action tells interchange to process the posted form vars according to the action set with mv_todo. The processing is not associated with any specific target page (though a page to display when processing is complete can be specified with mv_nextpage), so Interchange just builds a target URL that ends in an 'imaginary' page called 'process.html'.

There are other ways to handle a form post. For more information, see the Form Actions section Interchange Templates manual.

Basically, when you submit a <form> using the [process] tag, you get sent to the 'imaginary' process.html page. That page is derived from the page specified in the form's mv_nextpage CGI submission.

78.3. What PGP / GPG encryption software is available for Windows?

(Answered by Daryl Houston, Jonathan Clark, Aaron Hazelton, Mike Heins and Michael Goldfarb)

* PGP for various platforms:

* WinPT (Windows Privacy Tray)

* GPG Windows version

* MIT distribution of PGP

78.4. When are the results_big.html or results_either.html files called/used?

(Answered by Mike Heins)

They are just there as examples and are not used in the demo. If you don't use them, you can delete them.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Foundation Store

79. The Foundation Store

The Foundation store is distributed with Interchange to give you a starting point with which to build your e-business. While the Foundation store is designed to be relatively easy to start with, it is still a full-featured demonstration of a number of Interchange capabilities. Once you understand the Foundation store and how it works you are well on your way to understanding the Interchange software.

The following is a list of some popular features:

Category Searches

Images

Related Items

Reviews/Testimonials

79.1. Customizing Foundation

The foundation store has been customized to add just about every ecommerce and content management feature under the sun. If you are asking the question "can I do ...." the answer is almost assuredly "Yes".

Note that customizing the foundation store will take some experience in web design and database operations. Perl experience is also helpful. Most of all it will take persistence and empowering yourself to make changes and watch what happens.

It is usually helpful to make a test store, perhaps just an unmodified copy of foundation, to test out your additions before you make them on your own store. That way you can try anything you want without the chance of causing problems on your own store.

80. Tree design

By determining how users will enter and exit the catalog, complex and intelligent conditional schemes are possible, especially if the Cookies capability is exercised. However, it is recommended that simplicity be used. Consumers will not make purchases if they can't navigate their way around the catalog.

It is important to remember that users will lose their session (and items in their shopping cart) if their browser does not accept cookies and they leave the site. Interchange addresses this problem by using the area and page tags. If you are using frames, source all frame panes containing Interchange links from an initial page served by Interchange. If you don't do this, the user may have multiple session IDs depending on which frame generated the link.

Note that Interchange can work properly even if the browser doesn't store cookies. In this situation Interchange inserts a session ID into each URL; if the ID is preserved as the user navigates from page to page the session will remain intact.

81. The Catalog Directory

Interchange pages are contained in the catalog directory. Each individual catalog has its own base directory. The catalog directory has the following structure by default:

catalog.cfg

config

          StaticPage  <static.pages

error.log

etc

pages

        /cgi-bin/simple/products/gold will call the page in the file
        pages/products/gold.html.

products

session

tmp

82. Page Templates

This section describes the files located in the Foundation demo.

82.1. Template File Locations

This diagram shows the directory and file structure used for the default Foundation 'templates' directory. The base will be a directory with the name of your catalog, here called CATROOT.

    CATROOT/
    |
    |----templates/
         |----cart
         |----components/
              |----affiliate_receptor
              |----best_horizontal
              |----best_vertical
              |----cart
              |----cart_display
              |----cart_tiny
              |----category_vertical
              |----cross_horizontal
              |----cross_vertical
              |----modular_buy
              |----modular_update
              |----none
              |----promo
              |----promo_horizontal
              |----promo_vertical
              |----random
              |----random_horizontal
              |----random_vertical
              |----saved_carts_list_small
              |----search_box_small
              |----upsell
              |----upsell_horizontal
              |----upsell_vertical
         |----default --> foundation
         |----foundation/
              |----cart
              |----fullwidth
              |----leftonly
              |----leftright
              |----regions/
                   |----LEFTONLY_BOTTOM
                   |----LEFTONLY_TOP
                   |----LEFTRIGHT_BOTTOM
                   |----LEFTRIGHT_TOP
                   |----NOLEFT_BOTTOM
                   |----NOLEFT_TOP
              |----simple
              |----theme.cfg
         |----fullwidth
         |----leftonly
         |----leftright
         |----regions/
         |----LEFTONLY_BOTTOM
         |----LEFTONLY_TOP
         |----LEFTRIGHT_BOTTOM
         |----LEFTRIGHT_TOP
         |----NOLEFT_BOTTOM
         |----NOLEFT_TOP
         |----sampledata/
         |----computers/
              |----images/
                   |----items/
                        |----generic.gif
                        |----gift_certificate_large.gif
                        |----yourimage.gif
                   |----thumb/
                        |----generic_thumb.gif
                        |----gift_certificate.gif
                        |----thumb.gif
              |----products/
                   |----inventory.txt
                   |----merchandising.txt
                   |----mv_metadata.asc
                   |----options.txt
                   |----pricing.txt
                   |----products.txt
                   |----userdb.txt
         |----reports/
              |----download/
                   |----00352as.pdf
                   |----11993ab.pdf
                   |----22083da.pdf
                   |----49503cg.pdf
                   |----59330rt.pdf
                   |----59402fw.pdf
                   |----66548ch.pdf
                   |----73358ee.pdf
                   |----83491vp.pdf
                   |----90773sh.pdf
              |----products/
                   |----mv_metadata.asc
                   |----products.txt
                   |----userdb.txt
         |----tools/
              |----etc/
                   |----after.cfg
                   |----before.cfg
              |----images/
                   |----items/
                        |----os28004.gif
                        |----os28005.gif
                        |----os28006.gif
                        |----os28007.gif
                        |----os28008.gif
                        |----os28009.gif
                        |----os28011.gif
                        |----os28044.gif
                        |----os28057a.gif
                        |----os28057b.gif
                        |----os28057c.gif
                        |----os28062.gif
                        |----os28064.gif
                        |----os28065.gif
                        |----os28066.gif
                        |----os28068.gif
                        |----os28068a.gif
                        |----os28068b.gif
                        |----os28069.gif
                        |----os28070.gif
                        |----os28072.gif
                        |----os28073.gif
                        |----os28074.gif
                        |----os28075.gif
                        |----os28076.gif
                        |----os28077.gif
                        |----os28080.gif
                        |----os28081.gif
                        |----os28082.gif
                        |----os28084.gif
                        |----os28085.gif
                        |----os28086.gif
                        |----os28087.gif
                        |----os28108.gif
                        |----os28109.gif
                        |----os28110.gif
                        |----os28111.gif
                        |----os28112.gif
                        |----os28113.gif
                        |----os29000.gif
                   |----thumb/
                        |----gift_certificate.gif
                        |----os28004_b.gif
                        |----os28005_b.gif
                        |----os28006_b.gif
                        |----os28007_b.gif
                        |----os28008_b.gif
                        |----os28009_b.gif
                        |----os28011_b.gif
                        |----os28044_b.gif
                        |----os28057a_b.gif
                        |----os28057b_b.gif
                        |----os28057c_b.gif
                        |----os28062_b.gif
                        |----os28064_b.gif
                        |----os28065_b.gif
                        |----os28066_b.gif
                        |----os28068_b.gif
                        |----os28068a_b.gif
                        |----os28068b_b.gif
                        |----os28069_b.gif
                        |----os28070_b.gif
                        |----os28072_b.gif
                        |----os28073_b.gif
                        |----os28074_b.gif
                        |----os28075_b.gif
                        |----os28076_b.gif
                        |----os28077_b.gif
                        |----os28080_b.gif
                        |----os28081_b.gif
                        |----os28082_b.gif
                        |----os28084_b.gif
                        |----os28085_b.gif
                        |----os28086_b.gif
                        |----os28087_b.gif
                        |----os28108_b.gif
                        |----os28109_b.gif
                        |----os28110_b.gif
                        |----os28111_b.gif
                        |----os28112_b.gif
                        |----os28113_b.gif
                        |----os29000_b.gif
               |----products/
                    |----affiliate.txt
                    |----area.txt
                    |----cat.txt
                    |----inventory.txt
                    |----merchandising.txt
                    |----mv_metadata.asc
                    |----options.txt
                    |----orderline.txt
                    |----pricing.txt
                    |----products.txt
                    |----transactions.txt
                    |----userdb.txt

82.2. Themes

This section explains how themes are defined in Interchange via the STYLE variable and the theme configuration file, theme.cfg.

82.2.1. STYLE

The STYLE variable in CATROOT/products/variable.txt indicates the template style to be used as the theme for the catalog; the appropriate templates for that theme are found in CATROOT/templates/__STYLE__/. (To change the value of the STYLE variable, either edit variable.txt directly or use the table editor feature of the admin interface.)

The default theme for Interchange is the Foundation demo; hence, the STYLE variable is assigned the value 'Foundation' in variable.txt. The theme is defined in catalog.cfg as follows (line numbers added):

    # Here we set up the catalog theme.

  1 ParseVariables Yes

  2 ifndef STYLE
  3 Variable STYLE default
  4 endif
  5 include templates/__STYLE__/theme.cfg

Variables that make up the look and feel of the STYLE (theme) are defined in the file CATROOT/templates/foundation/theme.cfg, which is read by Interchange in line 5 above.

82.2.2. theme.cfg

The file CATROOT/templates/foundation/theme.cfg serves three purposes:

  1. It defines the THEME and THEME_IMG_DIR variables,
  2. It defines a cascading style sheet for the theme, and
  3. It defines the location of region templates according to the traffic settings for the Interchange daemon.

The THEME variable is used to set the location of the region templates in the traffic settings section of the theme.cfg file. It is also used in the cart template definition file (CATROOT/templates/cart) to set the path of an image. The THEME_IMG_DIR variable is used to set image paths in the template region files and the template component files.

The look and feel of the Foundation theme are defined primarily in the cascading style sheet specified in the theme.cfg file. This

The Interchange TRAFFIC setting, defined system-wide in interchange.cfg, is described in the ??document??. The settings in theme.cfg pertain to the location of region templates for the high and low traffic settings. For example, if you need to define a separate set of high traffic templates, you would change the ConfigDir variable in theme.cfg to point to the directory containing those templates.

82.3. Template Definition Files

The template definition files store the name and description of the template as well as components and options for that template.

    templates/cart
    templates/fullwidth
    templates/leftonly
    templates/leftright

    templates/foundation/cart
    templates/foundation/fullwidth
    templates/foundation/leftonly
    templates/foundation/leftright
    templates/foundation/simple

82.3.1. Template Walkthrough -- leftonly

This section is best read while viewing the file CATROOT/templates/leftonly and the 'Edit Page' page in the Content Editor of the Interchange Administration Tool.

Looking at the example template definition file, all lines located between the [comment] and [/comment] tags (lines 1 and 53) control what is available in the Edit Page screen of the Administration Tool.

Lines 2-5: Template specification

    2  ui_template: Yes
    3  ui_template_name: leftonly
    4  ui_template_layout: LEFTONLY_TOP, UI_CONTENT, LEFTONLY_BOTTOM
    5  ui_template_description: Page with top/left areas.

Line 2 indicates that this file is a template for the user interface. Line 3 names the template, while Line 4 indicates the regions that comprise the template and that will eventually make up the new page that is created from the template. Line 5 provides a description used to identify the template when it appears in a Select Template pull-down menu on the Edit Page of the Administration Tool. This description can be changed or modified to better describe a new template or a template that is created from the stock templates provided with Interchange.

Lines 7-8: Break

    7  break:
    8          widget: break

This code creates a separation line in the Edit Page between sets of options. In the default Interchange installation the line is grey, but the color can be changed. Note -- Changing this color applies the change to any catalog served by Interchange.

Lines 10-11: Page Title

    10 page_title:
    11         description: Page title

This code tells Interchange to display a text field on the Edit Page for entering the page title ('Title of New Page' in this example). The value entered is assigned to the scratch variable page_title and is set as a default value at the bottom of the template definition file using the following ITL:

    54 [set page_title][set]

which, in turn, sets the scratch variable on the new page using the tag

    [set page_title]Title of New Page[set]

The scratch variable page_title is parsed by the following code in the region template specified in the template definition file and called in the new page:

       <title>[scratch page_title]</title>

Lines 13-15: Page Banner

    13 page_banner:
    14         description: Page banner
    15         help: Defaults to page title

Assigns a textual title for the page to the scratch variable page_banner, which is assigned by the following ITL:

    55 [set page_banner][set]

The scratch variable page_banner is set on the new page using the tag

    [set page_banner]Banner of New Page[set]

The scratch variable can be parsed in the region template by this code:

    [either]
        [scratch page_banner]
    [or]
        [scratch page_title]
    [/either]

This results in the page banner being displayed if defined. Otherwise, the page title is used.

Lines 17-20: Members Only

    17 members_only:
    18         options: 1=Yes,0=No*
    19         widget: radio
    20         description: Members only

This creates a radio-button form element on the Edit Page with the user can specify whether the page can be accessed if a visitor is logged in (Yes) or not (No). The default is indicated by an asterisk.

The scratch variable members_only is assigned by the ITL code

    56 [set members_only][set]

and set on the new page using the tag

       [set members_only]0[/set]

if the page can be accessed without logging in or

       [set members_only]1[/set]

if it can not.

The members_only function is handled by the following code within each region template file:

    [if scratch members_only]
      [set members_only][/set]
      [if !session logged_in]
        [set mv_successpage]@@MV_PAGE@@[/set]
        [bounce page=login]
      [/if]
    [/if]

This code says that if "members only" is set to yes, and the visitor is logged in, to display the page. Otherwise, redirect the visitor to the login page.

Lines 22-23: Break

    22 break1:
    23         widget: break

Another separation line.

Lines 25-28: Horizontal Before Component

    25 component_before:
    26         options: =none, best_horizontal=Best Sellers, \
                cross_horizontal=Cross sell, \
                promo_horizontal=Promotion, \
                random_horizontal=Random items, \
                upsell_horizontal=Upsell
    27         widget: select
    28         description: Component before content

This allows the inclusion of a defined component (included in the CATROOT/templates/components directory) to be displayed before, or above, the page's content. It provides a pull-down menu on the Edit Page displaying the available components. The components, identified here on line 26, can be assigned a name via the value=name convention.

The scratch variable component_before is assigned in the template definition file by the ITL code

    57 [set component_before][set]

It is called with the following code within the LEFTRIGHT_TOP, LEFTONLY_TOP, and NOLEFT_TOP region templates:

    [if scratch component_before]
      [include file="templates/components/[scratch component_before]"]
    [/if]

Lines 30-33: Horizontal After Component

    30 component_after:
    31         options: =none, best_horizontal=Best Sellers, \
                    cross_horizontal=Cross sell, \
                promo_horizontal=Promotion, \
                                random_horizontal=Random items, \
                upsell_horizontal=Upsell
    32         widget: select
    33         description: Component after content

Similar to component_before, this allows the inclusion of a defined component after, or below, the page's content.

The scratch variable component_before is assigned in the template definition file by the ITL code

    58 [set component_after][set]

It is called with the following code within the LEFTRIGHT_BOTTOM and LEFTONLY_BOTTOM region templates:


    [if scratch component_after]
      [include file="templates/components/[scratch component_after]"]
    [/if]

Lines 35-38: Horizontal Item Width

    35 component_hsize:
    36         options: 1,2,3*
    37         widget: select
    38         description: Component items horizontal

This setting allows you to choose how many items the horizontal components display. For example, the horizontal best sellers component ("best_horizontal") uses this setting to randomly select the best sellers. Notice the default is 3 if nothing is defined. It is called by the following code in the promo_horizontal and random_horizontal components in the Foundation demo.

    random="[either][scratch component_hsize][or]2[/either]"

Lines 40-45: Before/After Banner

    40 hbanner:
    41         options: =--custom--, Also see..., Best Sellers, \
                            New items, \
                Some of our fine products, \
                                Specials, You might also like
    42         widget: move_combo
    43         width: 40
    44         description: Before/after Banner
    45         help: Banner for Before/after component

Allows a title for the horizontal components to be defined to be displayed in a header above the component's items. It is called with the [scratch hbanner] tag and used in the Foundation demo in the random_horizontal component.

Lines 47-51: Special Tag

    47 hpromo_type:
    48         options: specials=Specials, new=New items
    49         widget: select
    50         description: Special tag
    51         help: Only for a horizontal Promotion

This setting is only viable when a promotion is used for a horizontal component. It tells the promotional component which row(s) to evaluate in the merchandising table for display within the component. This setting, used in the promo_horizontal component, typically correlates to the featured column of the merchandising table as follows:

    [query arrayref=main
           sql="
            SELECT sku,timed_promotion,start_date,finish_date
            FROM merchandising
            WHERE featured = '[scratch hpromo_type]'
            "]
    [/query]

82.4. Edit Page Function

Creating a page with the following specifications using the Edit Page function results in the HTML and ITL code displayed below.

Specifications:

    Template:                    Page with top/left areas.
    Page title:                  test
    Page banner:                 test
    Members only:                No
    Component before content:    Best Sellers
    Component after content:     Random items
    Component items horizontal:  3
    Before/after Banner:         New items
    Special tag:                 Specials
    Content:                     <P>My first HTML/ITL page!

Resulting code:

    [comment]
    ui_template: Yes
    ui_template_name: leftonly
    [/comment]

    [set hbanner]New items[/set]
    [set page_title]test[/set]
    [set hpromo_type]specials[/set]
    [set component_hsize]3[/set]
    [set page_banner]test[/set]
    [set members_only]0[/set]
    [set component_before]best_horizontal[/set]
    [set component_after]random_horizontal[/set]
    @_LEFTONLY_TOP_@

    <!-- BEGIN CONTENT -->
    <P>My first HTML/ITL page!
    <!-- END CONTENT -->

    @_LEFTONLY_BOTTOM_@

An important point demonstrated here is the inclusion of the region templates LEFTONLY_TOP and LEFTONLY_BOTTOM through the @_VARIABLE_NAME_@ notation. These are included because of line 4 of the leftonly template definition file:

    4  ui_template_layout: LEFTONLY_TOP, UI_CONTENT, LEFTONLY_BOTTOM

However, understand that you are free to change the region templates used in the file by editing the file itself or, better yet, using an existing region as a starting point for a region of your own design.

The next section explains the structure of region templates.

82.5. Region Templates

Interchange region templates (or "regions") are portions of HTML and ITL that are included in pages within a catalog. Using regions, along with the cascading style sheet defined in theme.cfg, allows you to control the look and feel of specific parts of each catalog page.

The default Foundation region set, found in CATROOT/templates/foundation/regions, includes the following:

    LEFTONLY_TOP
    LEFTONLY_BOTTOM
    LEFTRIGHT_TOP
    LEFTRIGHT_BOTTOM
    NOLEFT_TOP
    NOLEFT_BOTTOM

The Foundation demo uses the Variable feature extensively to simplify hand page editing. Basically, a Variable is a define that permits the substitution of text for a simple __VARIABLE__ string in a page. For example, in the test page above, the variables LEFTONLY_TOP and LEFTONLY_BOTTOM correspond to region templates that provide a logobar, menubar, leftside menu, and copyright footer. Content, consisting of HTML and ITL, is placed within the BEGIN and END CONTENT comments. The following illustration shows how this looks on the page:

   +--------------------------------------------------------+
   |                      LOGOBAR                           |
   |--------------------------------------------------------+
   |                      MENUBAR                           |
   |--------------+-----------------------------------------+
   |              |                                         |
   |              |                                         |
   |              |                                         |
   |   LEFTSIDE   |          This is your content           |
   |              |                                         |
   |              |                                         |
   |              |                                         |
   |              +-----------------------------------------|
   |              |               COPYRIGHT                 |
   +--------------------------------------------------------+

In this diagram, LEFTONLY_TOP contributes the LEFTSIDE, LOGOBAR, and MENUBAR sections, while LEFTONLY_BOTTOM contributes the COPYRIGHT section.

The following subsections provide an inventory of where each of the region templates, included with the Foundation demo, are used in the pages and template definition files that make up the catalog.

82.5.1. LEFTONLY_TOP

The LEFTONLY_TOP template region is used in the following template pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/ship_addresses_added.html
    pages/ship_addresses_removed.html
    pages/stock-alert-added.html
    pages/stock-alert.html

The LEFTONLY_TOP template region is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/simple

82.5.1.1. Region Template Walkthrough -- LEFTONLY_TOP

 1  <!-- BEGIN LEFTONLY_TOP -->
 2  [if scratch members_only]
 3      [set members_only][/set]
 4      [if !session logged_in]
 5      [set mv_successpage]@@MV_PAGE@@[/set]
 6      [bounce page=login]
 7      [/if]
 8  [/if]
 9
10  <html>
11  <head>
12    <title>[scratch page_title]</title>
13    __THEME_CSS__
14  </head>
15
16  <body marginheight="0" marginwidth="0">
17
18  <!--- top left and right logo --->
19  <table width="100%" border="0" cellspacing="0" cellpadding="0">
20  <tr>
21    <td align="left" valign="middle" class="maincontent">
22      &nbsp;<img src="__THEME_IMG_DIR____LOGO__">
23    </td>
24    <td align="right" valign="middle" class="maincontent">
25      <img width="174" height="60" src="__THEME_IMG_DIR__logo2.gif">&nbsp;
26    </td>
27  </tr>
28  </table>
29
30  <!--- menu bar along the top --->
31  <table width="100%" border="0" cellspacing="0" cellpadding="0">
32  <tr>
33    <td width="100%" class="menubar">
34      <a href="[area index]"> \
         <img name="Home" border="0" src="__THEME_IMG_DIR__home.gif"></a>
35        <img src="__THEME_IMG_DIR__sep.gif">
36      <a href="[area login]">
37      [if session logged_in]
38        <img alt="Log Out" border="0" src="__THEME_IMG_DIR__logout.gif"></a>
39      [else]
40        <img alt="Log In" border="0" src="__THEME_IMG_DIR__login.gif"></a>
41      [/else]
42      [/if]
43        <img src="__THEME_IMG_DIR__sep.gif">
44      <a href="[area ord/basket]">
        <img alt="Your Cart" border="0" src="__THEME_IMG_DIR__cart.gif"></a>
45        <img src="__THEME_IMG_DIR__sep.gif">
46      <a href="[area ord/checkout]"> \
          <img alt="Check Out" border="0" src="__THEME_IMG_DIR__checkout.gif">\
                  </a>
47        <img src="__THEME_IMG_DIR__sep.gif">
48      <a href="[area customerservice]">
        <img alt="Customer Service" border="0"
                  src="__THEME_IMG_DIR__service.gif"></a>
49        <img src="__THEME_IMG_DIR__sep.gif">
50      <a href="[area aboutus]">
                        <img alt="About Us" border="0"
                        src="__THEME_IMG_DIR__about.gif"></a>
51    </td>
52  </tr>
53  </table>
54
55  <!--- left category column, main content column, and right special column --->
56  <table width="100%" border="0" cellspacing="0" cellpadding="0">
57  <tr>
58    <td width="20%" valign="top" align="left" class="categorybar">
59      <!--Left Sidebar-->
60      <table width="100%" border="0" cellspacing="0" cellpadding="0">
61        [include file="templates/components/[control component none]"][control]
62        [include file="templates/components/[control component none]"][control]
63        [include file="templates/components/[control component none]"][control]
64      </table>
65    </td>
66    <td width="80%" valign="top" align="center" class="maincontent">
67      [include file="templates/components/[control component none]"][control]
68

82.5.2. LEFTONLY_BOTTOM

The LEFTONLY_BOTTOM template region is used in the following template pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/ship_addresses_added.html
    pages/ship_addresses_removed.html
    pages/stock-alert-added.html
    pages/stock-alert.html

The LEFTONLY_BOTTOM template region is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/simple

82.5.3. LEFTRIGHT_TOP

The LEFTRIGHT_TOP template region is used in the following template pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html
    pages/swap_results.html

The LEFTRIGHT_TOP template region is used in the following templates:

    templates/foundation/leftright

82.5.4. LEFTRIGHT_BOTTOM

The LEFTRIGHT_BOTTOM template region is used in the following template pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html
    pages/swap_results.html

The LEFTRIGHT_BOTTOM template region is used in the following templates:

    templates/foundation/leftright

82.5.5. NOLEFT_BOTTOM

The NOLEFT_BOTTOM template region is used in the following template pages:

    pages/ord/checkout.html
    pages/splash.html

The NOLEFT_BOTTOM template region is used in the following templates:

    templates/foundation/fullwidth

82.5.6. NOLEFT_TOP

The NOLEFT_TOP template region is used in the following template pages:

    pages/ord/checkout.html
    pages/splash.html

The NOLEFT_TOP template region is used in the following templates:

    templates/foundation/fullwidth

82.6. Template Page List

/home/ic/catalogs/ft/pages/:

    aboutus.html
    account.html
    browse.html
    canceled.html
    change_password.html
    contact.html
    customerservice.html
    deliver.html
    flypage.html
    help.html
    index.html
    login.html
    logout.html
    lost_password.html
    modular_modify.html
    new_account.html
    privacypolicy.html
    process_return.html
    quantity.html
    results_big.html
    results_either.html
    results.html
    returns.html
    saved_carts.html
    ship_addresses_added.html
    ship_addresses.html
    ship_addresses_removed.html
    splash.html
    stock-alert-added.html
    stock-alert.html
    swap_results.html

/home/ic/catalogs/ft/pages/admin/report_def:

    Order%20Status.html
    Products%20to%20edit.html

/home/ic/catalogs/ft/pages/admin/reports:

    Order%20Status.html
    Products%20to%20edit.html

/home/ic/catalogs/ft/pages/affiliate:

    index.html
    login.html

/home/ic/catalogs/ft/pages/ord:

    basket.html
    checkout.html

/home/ic/catalogs/ft/pages/query:

    check_orders.html
    get_password.html
    order_detail.html
    order_return.html

82.7. Special Page List

/home/ic/catalogs/ft/special_pages/:

    badsearch.html
    canceled.html
    cc_not_valid.html
    confirmation.html
    failed.html
    interact.html
    missing.html
    needfield.html
    nomatch.html
    noproduct.html
    notfound.html
    order_security.html
    reconfig.html
    sec_faq.html
    security.html
    violation.html

82.8. Components

Interchange components are portions of HTML and ITL that are included in pages within a catalog depending on options set in the Administration Tool. The default component set includes the following:

    affiliate_receptor
    best_horizontal
    best_vertical
    cart
    cart_display
    cart_tiny
    category_vertical
    cross_horizontal
    cross_vertical
    modular_buy
    modular_update
    none
    promo
    promo_horizontal
    promo_vertical
    random
    random_horizontal
    random_vertical
    saved_carts_list_small
    search_box_small
    upsell
    upsell_horizontal
    upsell_vertical

/home/ic/catalogs/ft/templates/components:

82.8.1. affiliate_receptor

Not used in Foundation demo

82.8.2. best_horizontal

The best_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

Not used in Foundation demo pages

82.8.3. best_vertical

The best_vertical component is used in the following template:

    templates/foundation/leftright

Not used in Foundation demo pages

82.8.4. cart

The cart component is used in the following page:

    pages/ord/basket.html

82.8.5. cart_display

The cart_display component creates a small shopping cart that is displayed on the search results page (pages/results.html). It is displayed after an item in a list of results from a search is added to the shopping cart. cart_display is called in results.html by the following include statement:

    [include file="templates/components/cart_display"]

The cart_display component is used in the following pages:

    pages/results.html

82.8.5.1. Component Walkthrough -- cart_display

The remainder of this section is best read in conjunction with the file CATROOT/templates/components/cart_display in a text editor.

Lines 1-6: Component Specification

     1  [comment]
     2  ui_component: cart_display
     3  ui_component_group: info
     4  ui_component_label: Smaller cart for display in content area
     5
     6  [/comment]
     7

These lines control what is shown in the Edit page screen of the admin interface.

     8  <!-- BEGIN COMPONENT [control component cart_display] -->

Line 8 is an HTML comment noting the start of the code for the component. (Note that this can serve as a useful debugging tool to help you locate the component in the resulting HTML generated by Interchange when you view the source of a page loaded in the browser.)

     9  [if items]

Line 9 checks to see if there are items in the shopping basket. If there are, the remaining code up to the closing [/if] tag on line 64 is executed. If not, Interchanges continues executing the remaining code in results.html (the file that calls the cart_display component).

    10  <center>
    11    <table width="95%" border="0" cellspacing="0" cellpadding="0">
    12      <TR class="contentbar2" VALIGN=TOP>
    13        <td align=center class="contentbar2">Action</td>
    14        <td class="contentbar2">
    15          SKU
    16        </td>
    17        <td class="contentbar2">
    18          Description
    19        </td>
    20        <td class="contentbar2">
    21          Quantity
    22        </td>
    23        <td class="contentbar2">
    24          Price
    25        </td>
    26        <td class="contentbar2">
    27          Extension
    28        </td>
    29      </TR>

Line 10 centers the table started in line 11. Lines 12-29 create a header row in the shopping cart consisting of the header titles Action, SKU, Description, Quantity, Price, and Extension.

    30      <TBODY>
    31  [item-list]
    32

Line 30 defines the remainder of the table as a section while the [item-list] tag on line 31 tells Interchange to execute the code up to the closing tag ([/item-list] on line 59 for each item the customer has ordered so far.

    33      <tr class="[item-alternate 2]
                                                        maincontent
                                                        [else]contentbar1[/else]
                                                [/item-alternate]">
    34        <td align=center valign=top>
    35          [page ord/basket]edit</A>
    36        </TD>
    37        <td valign=top>[item-code]</TD>
    38        <td valign=top>[page [item-code]][item-description]</A>
    39        </TD>
    40

Line 33 begins the next row in the table. The [item-alternate] tag provided as the value of the class attribute tells Interchange to alternate between displaying the rows according to the "maincontent" and "contentbar1" styles (gray and white, respectively).

Lines 34-36 create a link to the shopping cart (basket.html) where the customer can remove or change the quantity of the item ordered.

Line 37 displays the SKU of the item. Lines 38 and 39 provide a link to the product display page (flypage.html) for the item. The [item-description] tag providing the content of the [page] tag enables the item's name to be displayed as the link to the product display page.

    41  [if-item-modifier gift_cert]
    42        <TD ALIGN=CENTER><small>Amount of gift:</small></TD>
    43        <TD ALIGN=CENTER>[item-quantity]</TD>
    44        <TD ALIGN=right>
    45          [item-subtotal]
    46        </TD>
    47  [else]
    48        <TD ALIGN=CENTER>[item-quantity]</TD>
    49        <TD ALIGN=right>
    50          [item-price]
    51        </TD>
    52        <TD ALIGN=right>
    53          [item-subtotal]
    54        </TD>
    55  [/else]
    56  [/if-item-modifier]
    57      </TR>
    58

Line 41 checks whether the item is a gift certificate. If it is it displays "Amount of gift:" and the [item-quantity] (number of gift certificates, in this case) under the headings "Quantity" and "Price", respectively. Otherwise, lines 48 through 50 display the quantity and price of the item ordered. Lines 45 or 53 (depending on whether the item is a gift certificate) display the item subtotal (quantity multiplied by price) for the item under the heading "Extension".

    59  [/item-list]
    60  </TBODY>
    61  </table>
    62  </FORM>
    63  </center>
    64  [/if]
    65
    66  <!-- END COMPONENT [control component cart_display] -->

Lines 59 through 64 close out the tags for the component, and line 66 indicates the end of the component code.

82.8.6. cart_tiny

The cart_tiny component is used in the following pages:

    pages/account.html
    pages/browse.html
    pages/canceled.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/saved_carts.html
    pages/ship_addresses.html

82.8.7. category_horizontal

Not used in Foundation demo pages or templates.

82.8.8. category_vertical

The category_vertical component provides a listing of all products in the catalog, organized by prod_group (e.g., Hand Tools, Ladders). category_vertical is usually displayed in the LEFTSIDE section of the page, under the search_box_small component.

The category_vertical component is used in the following pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/browse.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/results.html
    pages/results_big.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/stock-alert-added.html
    pages/stock-alert.html
    pages/swap_results.html

82.8.8.1. Component Walkthrough -- category_vertical

The remainder of this section is best read while viewing the file CATROOT/templates/components/cart_display in a text editor.

Lines 1-6: Component Specification

     1  [comment]
     2  ui_component: category_vertical
     3  ui_component_group: Navigation
     4  ui_component_label: Vertical category list
     5
     6  page_class:
     7          label: Page class
     8          widget: select
     9          lookup: which_page
    10          db: area
    11          help: Defines which sets of items should be displayed
    12          advanced: 1
    13
    14  set_selector:
    15          label: Page area selector
    16          widget: select
    17          db: area
    18          lookup: sel
    19          help: Defines which sets of items should be displayed
    20          advanced: 1
    21  [/comment]
    22

These lines control what is shown in the Edit page screen of the Administration Tool.

    23  <tr><td align="center" class="categorybar">
    24    <br>
    25    <table>
    26
    27  <!-- BEGIN COMPONENT [control component category_vertical] -->

Lines 23-25 set up the row and table within that row that will hold the vertical category list. Line 27 identifies the start of the code for the list.

    28  [loop
    29          prefix=box
    30          search="
    31                  fi=area
    32                  st=db
    33                  tf=sort
    34                  ac=0
    35                  ac=0
    36                  co=yes
    37
    38                  sf=sel
    39                  op=eq
    40                  se=[control set_selector left]
    41
    42                  sf=which_page
    43                  op=rm
    44                  se=[control page_class all|@@MV_PAGE@@]
    45  "]
    46

Lines 28-45 build a list of product categories obtained through a search of the area table.

    47    <tr>
    48      <td valign="top" class="categorybar">
    49        <b>[box-exec bar_link]area[/box-exec]</b>
    50      </td>
    51    </tr>
    52    <tr>
    53      <td valign="top" class="categorybar">
    54
    55  [set found_cat][/set]
    56  [loop prefix=cat
    57          search="
    58                  fi=cat
    59                  st=db
    60                  tf=sort
    61                  tf=name
    62                  rf=code,name
    63                  sf=sel
    64                  se=[box-code]
    65          "
    66          ]
    67        &nbsp;&nbsp;[cat-exec bar_link]cat[/cat-exec]<BR>
    68  [/loop]
    69
    70      </td>
    71    </tr>
    72  [/loop]
    73
    74    </table>
    75    <br>
    76  </td></tr>
    77
    78  <!-- END COMPONENT [control component category_vertical] -->

Lines 47-78 generate a list of links based on the products and product categories identified in the search.

82.8.9. cross_horizontal

The cross_horizontal component is used in the following pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html

The cross_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

82.8.10. cross_vertical

Not used in Foundation demo pages.

The cross_horizontal component is used in the following templates:

    templates/foundation/leftright

82.8.11. modular_buy

The modular_buy component is used in the following pages:

    pages/flypage.html

The modular_buy component is used in the following templates:

    templates/components/modular_update

82.8.12. modular_update

The modular_update component is used in the following pages:

    pages/modular_modify.html

82.8.13. promo

The promo component is used in the following pages:

    pages/contact.html
    pages/results_big.html

82.8.14. promo_horizontal

The promo_horizontal component is used in the following pages:

    pages/aboutus.html
    pages/canceled.html

The promo_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

82.8.15. promo_vertical

Not used in Foundation demo pages.

The promo_horizontal component is used in the following templates:

    templates/foundation/leftright

82.8.16. random

The random component is used in the following pages:

    pages/browse.html
    pages/index.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/results.html
    pages/swap_results.html

82.8.17. random_horizontal

Not used in Foundation demo pages.

The random_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

82.8.18. random_vertical

Not used in Foundation demo pages.

The random_vertical component is used in the following templates:

    templates/foundation/leftright

82.8.19. saved_carts_list_small

The saved_carts_list_small component is used in the following pages:

    pages/ord/basket.html

82.8.20. search_box_small

The search_box_small component is used in the following pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/browse.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/results.html
    pages/results_big.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/stock-alert-added.html
    pages/stock-alert.html
    pages/swap_results.html

The search_box_small component is used in the following templates:

    templates/regions/LEFTONLY_TOP
    templates/regions/LEFTRIGHT_TOP

82.8.21. upsell

Not used in Foundation demo pages.

82.8.22. upsell_horizontal

The upsell_horizontal component is used in the following pages:

    pages/flypage.html

The upsell_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

82.8.23. upsell_vertical

Not used in Foundation demo pages.

The upsell_vertical component is used in the following templates:

    templates/foundation/leftright

83. The Database Tables

Interchange catalogs are centralized around the database. You can alter any of the standard databases, add new databases, or remove unneeded databases

The foundation catalog includes the following tables, organized here by content:

You may also see symbolic links pointing to index tables, for example products.category.txt linking to products.txt.10. These are automatically generated indexes, in this case into the products table to speed category searches. See Dictionary Indexing With INDEX in the database documentation for details about auto-indexing of text databases.

The following dictionary lists and describes each table used in the Foundation demo.

83.1. 2ndDayAir.csv

Shipping table from UPS (http://www.ups.com/using/services/rave/rate/). This and all shipping tables should be updated periodically.

83.2. 450.csv

Shipping table from UPS for 450xx Zip Code origin. You will probably need to get your own from the UPS site (http://www.ups.com/using/services/rave/rate/) and clip the headers.

83.3. Ground.csv

Shipping table from UPS (http://www.ups.com/using/services/rave/rate/).

83.4. NextDayAir.csv

Shipping table from UPS (http://www.ups.com/using/services/rave/rate/).

83.5. access.asc

Administrative access table. This table is used by the Administration Tool. For more description on these fields, see the Interchange Administration Tool guide.

Fields

Field Description
username Login name or group name (group names begin with ':')
password Hashed password
name Administrator's name
last_login Last login time
super Set to 1 if superuser
yes_tables Tables the user may edit
no_tables Tables the user may not edit
upload No Description
acl No Description
export No Description
edit No Description
pages No Description
files No Description
config No Description
reconfig No Description
groups Administrator's group memberships
meta No Description
no_functions Explicitly disallowed functions
yes_functions Allowed functions with permission flags
table_control No Description
personal_css Administrator's personal CSS (for admin screen presentation)

83.5.1. username

Example Data

   :ausers
   :busers
   BigUser
   goody
   ic

The login name for an administrator or an administration group. Group names are prefixed with a colon (':').

83.5.2. password

Example Data

   Ksjs65bMNLjPQ

Hashed password.

83.5.3. name

Example Data

   Interchange Site Administrator
   Interchange Site Associates
   Business Users
   2nd Shift
   Mr. Jones
   Inbound Sales

Descriptive name for the administrator or administration group.

83.5.4. last_login

Example Data

   989424489

Last login time (in unix time() format).

83.5.5. super

Boolean value. If true (1), the administrator has Interchange Site Administrator privilege.

83.5.6. yes_tables

Example Data

   affiliate=vcx component=v gift_certs=v inventory=vx ...
   NONE

Tables this administrator or administration group can access. This is a space-delimited list of 'table_name=permission_flags' entries.

83.5.7. no_tables

Example Data

   access mv_metadata variable

Tables this administrator or administration group can not use. This is a space-delimited list of tables names.

83.5.8. upload

No Description

83.5.9. acl

No Description

83.5.10. export

No Description

83.5.11. edit

No Description

83.5.12. pages

No Description

83.5.13. files

No Description

83.5.14. config

No Description

Example Data

Allowed Values

83.5.15. reconfig

No Description

83.5.16. groups

Example Data

   ausers
   busers

Allowed Values

Groups the site user belongs to. You can set permissions for groups.

83.5.17. meta

No Description

83.5.18. no_functions

Example Data

   orderstats trafficstats

Space-delimited list of functions explicitly not allowed for the site user.

83.5.19. yes_functions

Example Data

   item=lvecd itemtype=lvc order=lvca orderstats trafficstats ...
   NONE

Functions the site user can perform. This is a space-delimited list of functions, with permission flags if appropriate.

Usage examples

83.5.20. table_control

No Description

Usage examples

83.5.21. personal_css

Used in the Administration Tool screens to make personal changes to the page presentation. This is done by creating your own personal CSS (cascading style sheet).

Usage examples

83.6. affiliate

cat_root/products/affiliate.txt

This table contains data related to your affiliate programs. See also the affiliate_receptor component.

Fields

Field Description
affiliate Affiliate ID
name Name of affiliate organization
campaigns Campaigns this affiliate participates in
coupon_amount Discount for customers from affiliate participating in coupon campaign
join_date When the affiliate signed with you
url Your default URL to use for customers coming from the affiliate site (not the affiliate's home page)
timeout Timeout in seconds after which purchases are no longer credited to the affiliate
active Boolean, set to 1 for active affiliates
password Affiliate login password
image Affiliate's logo

83.6.1. affiliate

Example Data

   consolidated
   hardhat

This field contains the unique Affiliate ID.

83.6.2. name

Example Data

   Consolidated Diversified
   Hardhat Construction

This is the descriptive name of the affiliate.

83.6.3. campaigns

Example Data

   coupon

This field lists the campaigns that the affiliate participates and enables campaign features and tracks traffic from advertising campaigns. The foundation catalog implements a coupon campaign in the affiliate_receptor component. If you want to add campaigns, you will also need to develop the appropriate logic within the affiliate_receptor component and pages that use it.

83.6.4. coupon_amount

Example Data

   5

This is the discount offered customers from the affiliate participating in the coupon campaign.

Note -- This is implemented in the affiliate_receptor component as a flat discount amount. If you wanted a percentage discount instead, you would modify the [discount] tag in catalog_root/templates/components/affiliate_receptor (see the [discount] tag for more detail).

83.6.5. join_date

Example Data

   20000827
   20000910

This is the date when the affiliate signed with you.

83.6.6. url

Example Data

   http://demo.akopia.com/~hardhat
   http://www.minivend.com/consolidated/

The value in this field is used to direct visitors coming from the Affiliate to your home page or a page you have designed specifically for visitors from that Affiliate's site. Note that this should not be the URL of the Affiliate's home site.

83.6.7. timeout

Example Data

   0
   3600

The value in this field is used to specify the amount of time a customer has to place an order to still give the Affiliate credit for it. If the customer goes over this amount of time, the Affiliate doesn't get credit for the customer visit. The timeout delay is measured in seconds, with the value of 0 (zero) disabling it. It is recommended that you use a value in the thousands to make sure the customer has enough time to shop.

83.6.8. active

This is a boolean value indicating whether the affiliate is active.

83.6.9. password

Example Data

   akopia

Password for affiliate login (see catalog_root//pages/affiliate/login.html). Note that the password is stored in plaintext by default.

83.6.10. image

Example Data

   http://demo.akopia.com/~hardhat/images/logo.gif
   http://www.minivend.com/consolidated/conslogo.gif

Affiliate's logo image.

83.7. area

cat_root/products/area.txt

This table is used to implement dynamic navigation bars. For example, it is used in the category_horizontal and category_vertical components. Note the similarity to the cat table, since both area and cat tables supply data for building links to results pages.

When building entries in a navigation bar, it is the bar_link subroutine in the /dist/catalog_before.cfg configuration file that actually reads and processes the values from the table.

See also the following catalog and administrative templates:

Fields

Field Description
code Unique key
sel Space-delimited list of navigation bars to contain the entry
name Display label
which_page Page class in which the navigation bar may appear
sort Sorting prefix for entry (preempts standard alphanumeric sort)
display_type How to label links in the navbar (name, icon, url or image)
image Image URL (if appropriate)
image_prop HTML attributes for output <img> tag (if appropriate)
banner_image Image name for use in target page
banner_text Text for use in target page
link_type Type of links in the navbar (external, internal, simple, complex)
url Target for internal or external link_type
tab Database table file to use with 'simple' link_type
page Results page to use with 'simple' link_type
search Search spec used with 'complex' link_type
selector The selector used to scan the products table for products in the category
link_template Overrides template used for building navbar links.

83.7.1. code

Example Data

   1
   2
   3

Unique key.

83.7.2. sel

Example Data

   left

Space-delimited list of navigation bars that should contain the entry. Note that comma or null should also work as a delimiter.

83.7.3. name

Example Data

   Hand Tools
   Hardware
   Ladders
   Measuring Tools
   Painting Supplies
   Safety Equipment
   Specials
   Tool Storage

Label to display.

83.7.4. which_page

Example Data

   all

Page class in which the navigation bar may appear.

83.7.5. sort

Example Data

   00
   03
   04
   05
   06

Lexographic (alphanumeric) sorting prefix. Note use of '03' rather than '3', which would sort after '13'. This controls the order of the categories in your navigation bar.

If this is not set, your navbar entries will sort in alphabetical order.

83.7.6. display_type

Example Data

   name
   icon
   url
   image

What to use for the labels in the navigation bar (for example, name, icon, url or image). The navigation bars in the foundation catalog are set up with 'name' display_type.

display type Link shown as
name Displays name only
icon Displays name and specified image
image Displays image only
url Displays link

83.7.7. image

Image URL for image or icon display_type.

83.7.8. image_prop

For image or icon display_type, this contains the HTML attributes for the HTML that will appear in the navbar, for example:

  <img src="image" alt="name" image_prop>name

83.7.9. banner_image

Example Data

   promo_image.gif

This field is not related to banner ads. It is useful if you want to pass to your results page an image that is specific for the navbar entry (perhaps to display a banner above your results).

If you are using an Interchange search for your links (i.e., 'simple' or 'complex' link_type), then this will add 'va=banner_image=banner_image' to the resulting search specification. This puts the contents of banner_image into the Values hash of your search results page. You can access it with [value banner_image] (see the value tag). You will have to modify the standard results page (or set up and specify your own) in order to display the image.

   <IMG src="[value banner_image]" alt="[value banner_text]">

The foundation catalog does not implement banner_image in the preconfigured navigation bars.

83.7.10. banner_text

Example Data

   This Is A Title For Hand Tools

This field is not related to banner ads. It is useful if you want to pass to your results page some text that is specific for the navbar entry (perhaps to display a title above your results).

If you are using an Interchange search for your links (i.e., 'simple' or 'complex' link_type), then this will add 'va=banner_text=banner_text' to the resulting search specification. This puts the contents of banner_text into the Values hash of your search results page. You can access it with [value banner_text] (see the value tag). You will have to modify the standard results page (or set up and specify your own) in order to display the text.

The foundation catalog does not implement banner_text in the preconfigured navigation bars.

83.7.11. link_type

Example Data

   none
   external
   internal
   simple
   complex

Link type to create in the navigation bar.

Link type Description
none No link
external External link. The HTML specified in url will go directly into the navigation bar.
internal Internal link. This will be highlit if it is the current page. If you specify both a page and a form for the link, the url field should contain "page form". See the Search Engine documentation for more detail on search forms.
simple Allows you to specify an Interchange search with a few values. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file for more detail.
complex Allows you to fully specify an Interchange search specification. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file for more detail if you need to use these.

83.7.12. url

Target URL (external link or internal page/search specification). See link_type . The foundation catalog navigation bars are not set up with link types that use the url field.

83.7.13. tab

Database table file to use with 'simple' link_type (searchspec fi=tab). The foundation catalog navigation bars are not set up with link types that use the tab field.

83.7.14. page

Results page to use with 'simple' link_type (searchspec sp=page). The foundation catalog navigation bars are not set up with link types that use the page field.

83.7.15. search

Search spec used with 'complex' link_type. See the Search Engine documentation for more detail on search forms. The foundation catalog navigation bars are not set up with link types that use the search field.

83.7.16. selector

The selector that is used to scan the products table for products in the category. Used with 'simple' link_type. The foundation catalog navigation bars are not set up with link types that use the selector field.

83.7.17. link_template

Overrides the usual HTML link template for navbar entries. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file if you need to modify link templates.

The foundation catalog navigation bars are not set up with link types that use the link_template field.

83.8. banner

cat_root/products/banner.txt

The banner ad table. The foundation catalog does not implement any banner ads with this table.

You do not need to use this table to display ads served by third parties (for example, doubleclick). Since most banner ads on the internet are served by third parties and are not managed by your catalog, you probably will not need to set up banners here unless you do your own advertising.

See Banner/Ad rotation in the template documentation for a detailed description of the columns and content of the banner table. Also, see the banner tag documentation.

Fields

Field Description
code Key for the item. If the banners are not weighted, this should be a category-specific code.
category Category for set of weighted banners
weight Display frequency weight for weighted banner
rotate Boolean: parse banner field for banners to rotate if true (1)
banner Banner name or list of banners to rotate

83.8.1. code

Example Data

   MyBanner
   MyBanner2
   MyBanner3
   default

See Banner/Ad rotation.

83.8.2. category

Example Data

   BannerCat1

See Banner/Ad rotation.

83.8.3. weight

Example Data

   1
   2
   7

See Banner/Ad rotation.

83.8.4. rotate

Boolean value. If true (1), rotates banners listed in banner. See Banner/Ad rotation.

83.8.5. banner

Example Data

   Default banner 1{or}Default banner 2{or}Default banner 3
   First MyBanner
   Second MyBanner
   Third MyBanner

See Banner/Ad rotation.

83.9. cat

cat_root/products/cat.txt

This table contains properties of product categories. Notice the similarity to the area table, since both the area and cat tables supply data for building links to results pages.

Fields

Field Description
code Unique key
sel Space-delimited list of foreign keys into area table
name Category name
which_page Page class in which the category may appear
sort Sorting prefix for entry (preempts standard alphanumeric sort)
display_type How to label the category links (name, icon, url or image)
image Image URL (if appropriate)
image_prop HTML attributes for output <img> tag (if appropriate)
banner_image Image name for use in target page
banner_text Text for use in target page
link_type Type of links in the navbar (external, internal, simple, complex)
url Target for internal or external link_type
tab Database table file to use with 'simple' link_type
page Results page to use with 'simple' link_type
search Search spec used with 'complex' link_type
selector The selector used to scan the products table for products in the category
link_template Overrides template used for building links

83.9.1. code

Example Data

   1
   4
   5

Unique key.

83.9.2. sel

Example Data

   6
   8 9
   9

Space-delimited list of foreign key(s) into area table. The category will appear in each navbar section (defined by a row in the area table) where the key from cat.sel matches the area.code.

For example, the foundation catalog (tools) places Gift Certificates in more than one category of the left navbar.

83.9.3. name

Example Data

   Breathing Protection
   Eye Protection
   Gift Certificate
   Picks & Hatchets
   Pliers
   Rulers
   Sandpaper
   Toolboxes

Category name for display.

83.9.4. which_page

The page class. When building links, you can select categories matching a page class. This means you could set up your catalog to show a different list of links on page 'foo.html' than on page 'bar.html'.

83.9.5. sort

Example Data

   01
   03

Lexographic (alphanumeric) sorting prefix. Notice use of '03' rather than '3', which would sort after '13'. You can use this to control the order of the categories in a list of links.

83.9.6. display_type

Example Data

   name
   icon
   url
   image

What to use for the labels in the navigation bar (for example, name, icon, url or image). The links in the foundation catalog are set up with 'name' display_type.

display type Link shown as
name Displays name only
icon Displays name and specified image
image Displays image only
url Displays link

83.9.7. image

Image URL for image or icon display_type.

83.9.8. image_prop

For image or icon display_type, this contains the HTML <img ...> tag attributes for the links, for example:

  <img src="image" alt="name" image_prop>name

83.9.9. banner_image

Example Data

   promo_image.gif

This field is not related to banner ads. It is useful if you want to pass to your results page an image that is specific for the navbar entry (perhaps to display a banner above your results).

If you are using an Interchange search for your links (i.e., 'simple' or 'complex' link_type), then this will add 'va=banner_image=banner_image' to the resulting search specification. This puts the contents of banner_image into the Values hash in your search results page. You can access it with [value banner_image] (see the value tag). You will have to modify the standard results page (or set up and specify your own) in order to display the image. For example, you might include the following in your results page:

   <IMG src="[value banner_image]" alt="[value banner_text]">

83.9.10. banner_text

This field is not related to banner ads. It is useful if you want to pass to your results page some text that is specific for the navbar entry (perhaps to display a title above your results).

If you are using an Interchange search for your links (i.e., 'simple' or 'complex' link_type), then this will add 'va=banner_text=banner_text' to the resulting search specification. This puts the contents of banner_text into the Values hash in your search results page. You can access it with [value banner_text] (see the value tag). You will have to modify the standard results page (or set up and specify your own) in order to display the text.

83.9.11. link_type

Example Data

   none
   external
   internal
   simple
   complex

The link type to create.

Link type Description
none No link
external External link. The HTML specified in url will go directly into the link.
internal Internal link. This will be highlit if it is the current page. If you specify both a page and a form for the link, the url field should contain "page form". See the Search Engine documentation for more detail on search forms.
simple Allows you to specify an Interchange search with a few values. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file for more detail.
complex Allows you to fully specify an Interchange search specification. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file for more detail if you need to use these.

83.9.12. url

Target URL (external link or internal page/search specification). See link_types above.

83.9.13. tab

Example Data

   products

Database table file to use with 'simple' link_type (searchspec fi=tab).

83.9.14. page

Example Data

   swap_results

Results page to use with 'simple' link_type (searchspec sp=page).

83.9.15. search

Example Data

   fi=merchandising^Msf=featured^Mse=new
   fi=merchandising^Msf=featured^Mse=special^Msu=yes

Search spec used with 'complex' link_type. See the Search Engine documentation for more detail on search forms.


Note: The '^M' delimiters in the sample data represents a carriage return character (Control-M, or hexadecimal 0x0d).

83.9.16. selector

Example Data

   category=Breathing Protection
   category=Eye Protection
   category=Gift Certificate
   category=Picks & Hatchets
   category=Pliers
   category=Rulers
   category=Sandpaper
   category=Toolboxes

The element that is used to scan the products table for products in the category. Used with 'simple' link_type.

83.9.17. link_template

Overrides the usual HTML link template for navbar entries. See the bar_link subroutine in the /dist/catalog_before.cfg configuration file if you need to modify link templates.

83.10. country

A list of countries used to build select boxes, calculate tax, and set shipping mode choices based on the user's country.

    code          Country code
    sorder        Used to determine sort order
    region        An enumerator to group based on region
    selector      The code that should be used (same as code)
    shipmodes     Shipping modes to be presented for that country
    name          Textual name of the country
    iso           ISO three letter code for the country
    isonum        ISO numeric code for the country
    tax           Tax information (may redirect to a state table)

83.11. downloadable

This table controls downloadable products. The Marketing Reports data set for the foundation catalog demonstrates downloadable products. List a product's sku in this table if you want to deliver it through a download. A customer can then download the file specified in the dl_location field after checkout.

For reference, see the implementation in the following files:

Fields

Field Description
sku Unique key, matches product.sku
dl_location Location of downloadable file
dl_type MIME type of downloadable file

83.11.1. sku

Example Data

Example Data from the Marketing Reports data set:

   00352as
   22083da
   49503cg
   59330rt
   59402fw
   73358ee
   83491vp
   90773sh

This is the unique key for this table that is also the common key into the products table.

83.11.2. dl_location

Example Data from 'reports' catalog

   download/00352as.pdf
   download/22083da.pdf
   download/49503cg.pdf
   download/59330rt.pdf
   download/59402fw.pdf
   download/73358ee.pdf
   download/83491vp.pdf
   download/90773sh.pdf

File location of downloadable product.

83.11.3. dl_type

Example Data from 'reports' catalog

   application/pdf

MIME type of downloadable content.

83.12. files

A database where files (pages, etc.) can be kept instead of in the Unix filesystem. Not normally used in foundation.

83.13. inventory.txt

    sku            Quantity info
    quantity       Gets decremented after each sale.
    stock_message  The usual shipping time of the product. Example choices:

                                      In stock
                                      Ships in 3-5 days
                                      Ships in 4-6 weeks
                                      Special order

    account        Sales account for accounting links
    cogs_account   Inventory account for accounting links

83.14. locale.txt

    code
    en_US
    de_DE
    fr_FR

Used to develop localization. Can be used in conjunction with other types of locale information. See Internationalization.

83.15. merchandising.txt

    sku
    featured
    banner_text
    banner_image
    blurb_begin
    blurb_end
        Closer (end text for feature display)
    timed_promotion
    start_date
        Start date
    finish_date
    upsell_to
        Cross-sell SKUs
    cross_sell
    cross_category
    others_bought
    times_ordered

83.16. mv_metadata

See the following sections in the icadvanced catalog for more information:

83.17. options

This table contains data for implementing simple, matrix and modular options.

Simple options are options that a customer can combine arbitrarily, such as size and color. The selected options might affect price. See the accessories tag for more detail on option values for simple options.

Matrix options are preconfigured combinations of options. For example, if you sell titanium and carbon-fiber bike frames, but offer only certain combinations of frame material and color, your checkout page might include a select box with only the following entries:

Note that there is no Yellow Flame Titanium offering, for example.

Modular options are like a structured bill of materials, where one product is a master item and other products are subitems for that master item. The subitems can also be master items to subitems at a lower level. In addition, subitems may be designated as 'phantom', which means that they are placeholders in the hierarchy of the structured bill of materials with their own subitems, but are not actual items themselves.

The foundation catalog with the computer data set uses modular options.

For more information, see the following pages and components in the foundation catalog:


Note: Subsequent foundation catalog releases may place simple, matrix, and modular option types in separate tables.

Fields

Field Description
code Unique ID for the product option
o_master SKU of the master item for the option
sku SKU for the option (foreign key into products table)
o_group Product grouping code
o_sort Sorting prefix for list display
phantom Boolean -- Item is a phantom placeholder (as in structured bill of materials) with suboptions.
o_enable Boolean -- enables suboptions for the option
o_matrix Matrix-type option (preconfigured combinations of attributes)
o_modular Modular-type option (master/subitem relationship like modular bill of materials)
o_default Default selection for the option group or suboption for a phantom option
o_label Short name for option display
o_value Simple option values (in Interchange option format)
o_widget The HTML widget to use for displaying the option group
o_footer Not used in foundation catalog
o_header Not used in foundation catalog
o_height Height of widget (if applicable)
o_width Width of widget
description Option/Variant description (for description in display)
price Price of this option/variant
wholesale Dealer price of this option/variant
differential Differential to add to the base item price when using a phantom bill of materials
weight Weight difference with this option/variant (for shipping)
volume Volume difference with this option/variant
mv_shipmode No Description
o_exclude Option groups to exclude (trumped by o_include). Modular only.
o_include Option groups to include (trumps o_exclude). Modular only.

83.17.1. code

Example Data

   1002
   1003
   1004
   1005

Unique ID for the option.

83.17.2. o_master

Example Data

   00010
   999000
   999001
   999002

SKU of the master item for the option. The master item is one level up in the modular hierarchy, and must be one of the following:

If an option has a master item, then a customer can not choose that option without having previously selected the master item.

The price for a master item is the sum of the master item's price and the price for each of the subitems. Because the subitems are recursively defined, the top-level item reflects the top level price plus the price of all selected options.

83.17.3. sku

Example Data

   00010
   999000
   7000015
   7000030

The sku for the item or option. This may not be unique for matrix options or if an option that belongs to multiple o_masters is listed for each master.

83.17.4. o_group

Example Data

   A
   B
   C
   I

Product group (scanned to see whether it applies to this product or not)

83.17.5. o_sort

Example Data

   01
   02
   03
   04
   47
   48
   49
   50

Sorting prefix for listing order of options.

83.17.6. phantom

Modular options only.

Boolean -- if true (1), then this is a phantom item acting as a placeholder for other items rather than an actual product. The item's sku will not match an entry in the products table, though the o_master will match either the sku of another phantom item in the options table or the sku of an item in the products table.

83.17.7. o_enable

Boolean -- Enables subitems for this item or option. Note that an option with o_enable false may itself still be a subitem for an option or item above it.

83.17.8. o_matrix

Boolean. Set true (1) for matrix-type options. See the options table in the tools data set for examples of matrix options. Matrix options that are part of a set have the same value for options.sku.

83.17.9. o_modular

Specifies a modular option. See main heading for description of modular options.

83.17.10. o_default

Example Data

   1
   11002
   7000062
   7000087

Selects the default option for a group.

83.17.11. o_label

Example Data

   Add a second hard drive
   Case Color
   Case color
   Case style
   Include tapes
   Red

This is the short name for option display.

83.17.12. o_value

Example Data

   1=One 8GB tape,\r2=Two 8GB tapes,\r=None*
   a=One 8GB tape,\rb=Two 8GB tapes,\r=None*
   baby=Baby Tower,\rmid=Mid-tower,\rfull=Full Tower
   baby=Baby tower,\rmid=Mid-tower,\rfull=Full tower
   red=Passion Red,\rblue=Electric Blue,\rgreen=Sea Green,\rgrey=S...
   red=Passion Red,\ryellow=Lemon Yellow,\rblue=Electric Blue,\rgr...
   red=Rage Red,\ryellow=Honey Yellow

This is an Interchange value set for a simple option. It is typically a comma-delimited list of labels and values with '*' indicating the default value. See the accessories tag for more detail.

Note that the "\r" characters in the above example represent carriage returns in the actual data ("\r" in perl, or Ctrl-M, or hexadecimal 0D), and the ... indicates a line too long to show.

83.17.13. o_widget

Example Data

   select

This determines the HTML Widget type (e.g., a select box). For example, the [options] tag uses this entry when building HTML widgets in a page. See also the [accessories] tag for available widgets.

83.17.14. o_footer

Example Data

Allowed Values

83.17.15. o_header

Example Data

Allowed Values

83.17.16. o_height

This allows you to set the height of the HTML widget, if appropriate.

83.17.17. o_width

This allows you to set the width of the HTML widget, if appropriate.

83.17.18. description

Example Data

   ATX Mid Tower-Grey (3)5.25 (2)3.5 & (1)3.5 Hidden
   Enlight ATX Desktop Case (2)5.25 & (2)3.5
   Enlight ATX Tower Case (4) 5.25 & (2)3.5
   Micro ATX Tower - Honey Yellow
   Micro ATX Tower - Moody Blue
   Micro ATX Tower - Rage Red
   Micro ATX Tower - Smoky Grey
   Super Tower Case (6)5.25 & (3)3.5

Longer description to show when displaying the options.

83.17.19. price

Example Data

   0.00
   10
   20
   29
   75

This sets the retail price of the option.

83.17.20. wholesale

Example Data

   13
   40.00

This sets the dealer price of the option.

83.17.21. differential

Example Data

   -209
   -40
   -79

The phantom bill of materials for an option group can have a differential, which is an amount to add to the base price of the master product to get to a new base price that accommodates the phantom bill of materials. Note that the differential can be negative.

For example, in the computer data set of the foundation catalog, SKU 00011 in the products table is an $849.95 pre-configured Athlon 800MHz computer that includes a 17" monitor (in this case, SKU 7000087 in the products table).

The monitor by itself would otherwise have cost $209. It is much more convenient if you can use the same option part number and price for each item. To do this, you need a phantom option (in this case, SKU 999105 in the options table only) with a differential of -209 and the available monitors as suboptions. When you include the phantom option in the bill of materials for the computer (SKU 00011), the $-209 differential adjustment makes the price work out properly.

For instance, suppose that a $499 computer is configured as follows:

        500 MHz Athlon         --  $499
        32 MB SDRAM            --  ZERO
        10 GB disk             --  ZERO

        TOTAL                  --  $499

Suppose it costs $90 to upgrade the base computer to 128M of RAM and $150 for a 30 GB hard disk.

If you also sell an 128MB 800 MHz $899 computer, and the customer upgrades to the 30 GB hard disk,

        800 MHz Athlon          --  $899
        (memory differential)   --  $-90
        128 MB RAM              --   $90
        30 GB  disk             --  $150

        TOTAL                   -- $1039

If you did not have the differential, you would need a different option part number for each item make the number come out right.

With the differential, you can use the same part number for 128MB RAM no matter what the base part is. The price is always $90 -- there is just a -90 differential when ordered with the 800MHz Athlon, making the effective price zero.

83.17.22. weight

Example Data

   5

Shipping weight of the option. Interchange uses this to calculate shipping cost.

83.17.23. volume

Volume added by the option.

83.17.24. mv_shipmode

No Description

83.17.25. o_exclude

Modular options only.

Lists the option groups to exclude once the include has been done. Takes the form of a number of wildcard atoms.

83.17.26. o_include

Modular options only.

Lists the option groups to include with your item. Takes the form of a number of wildcard atoms.

83.18. order_returns.txt

    code
    order_number
    session
    username
    rma_number
    nitems
    total
    return_date
    update_date

83.19. orderline.txt

Every line item that is actually ordered is detailed in this table. The order as a whole is one record in the transactions table.

See the page query/check_orders.html for how it can be used. See etc/report for how to add to it.

    code
    store_id
    order_number
    session
    username
    shipmode
    sku
    quantity
    price
    subtotal
    shipping
    taxable
    mv_mi
    mv_si
    size
    color
    options
    order_date
    update_date
    status
            pending = Pending
            shipped = Shipped
            backorder = Back ordered
            credit = Waiting for credit check
            canceled = Cancelled
    parent
    affiliate
    campaign
    description
    mv_mp

83.20. pricing

This database works in conjunction with the CommonAdjust directive to allow quantity pricing for one product or for a group of products (sometimes known as mix-and-match). The fields q2, q5, q10, etc. are for the quantity levels; the price_group field selects the mix-and-match category for the product.

Fields

Field Description
sku Unique key, shared with products table
price_group Mix-and-match category
q2 Retail, 2 or more
q5 Retail, 5 or more
q10 Retail, 10 or more
q25 Retail, 25 or more
q100 Retail, 100 or more
w2 Wholesale, 2 or more
w5 Wholesale, 5 or more
w10 Wholesale, 10 or more
w25 Wholesale, 25 or more
w100 Wholesale, 100 or more

83.20.1. sku

Example Data

   os28004
   os28006
   os28057c
   os28069

Unique key, matching the sku for an entry in products table.

83.20.2. price_group

Example Data

   general

This field determines mix-and-match categories if you want to allow mix-and-match quantity pricing (i.e., where 5 of these plus 5 of those afford the q10 price for both these and those).

83.20.3. q2

If set, this will be the price per item when the order quantity is 2 or greater.

83.20.4. q5

If set, this will be the price per item when the order quantity is 5 or greater.

83.20.5. q10

If set, this will be the price per item when the order quantity is 10 or greater.

83.20.6. q25

If set, this will be the price per item when the order quantity is 25 or greater.

83.20.7. q100

If set, this will be the price per item when the order quantity is 100 or greater.

83.20.8. w2

If set, this will be the dealer price per item when the order quantity is 2 or greater.

83.20.9. w5

If set, this will be the dealer price per item when the order quantity is 5 or greater.

83.20.10. w10

If set, this will be the dealer price per item when the order quantity is 10 or greater.

83.20.11. w25

If set, this will be the dealer price per item when the order quantity is 25 or greater.

83.20.12. w100

If set, this will be the dealer price per item when the order quantity is 100 or greater.

83.21. products

This is the main table for product data. See also 'The Product Database' section in the database documentation.

The sku is also the master key in many of the related tables.

Fields

Field Description
sku Unique product ID
description Short description for list display
title Full title for book, CD, artwork, etc.
template_page Not used in foundation catalog. No description.
comment Longer description for item display (e.g., flypage.html)
thumb Thumbnail image
image Regular-sized image
price Retail quantity one price
wholesale Dealer minimum quantity price
prod_group Product supercategory
category Product category
nontaxable Boolean. Set true (1) if nontaxable
weight Weight in your units. Should match shipping table.
size List of options used with accessories tag.
color List of options used with accessories tag.
gift_cert Boolean. Set true (1) if this is a gift certificate.
related Deprecated in favor of merchandising.upsell_to
featured Deprecated. Use merchandising table.
inactive Boolean. Set true (1) to inactivate a product
url Not Documented

83.21.1. sku

Example Data

   gift_cert
   os28004
   os28006
   os28057c

Unique identifier for the product. You should use only characters of the class A-Z a-z 0-9 _ - (i.e., matching the regular expression, '[-A-Za-z0-9_]+'). Although Interchange itself does not impose this restriction, you may have problems with SQL databases, file systems, and URL encoding if you use other characters. For example, a slash (/) can interfere with URLs and filenames, a colon (:) can interfere with database representations (or file names on some operating systems), i<etc.>

83.21.2. description

Example Data

   Brush Set
   Disposable Brush Set
   Ergo Roller
   Gift Certificate
   Painters Brush Set
   Painters Ladder
   Spackling Knife
   Trim Brush

A short description for the product that is used for displaying in the shopping cart, receipt, and order report.

83.21.3. title

Example Data

   Brush Set
   Disposable Brush Set
   Ergo Roller
   Gift Certificate
   Painters Brush Set
   Painters Ladder
   Spackling Knife
   Trim Brush

This column is not used in the foundation catalog. Previously used in the Art store (simple) demo for a painting title. You probably want to use description instead.

You should modify the products and other tables to suit your catalog's requirements. You might use this field if you want to show titles for books, music, or other titled merchandise. If you do not use a title that is distinct from the short description, then you probably do not need this column in the table at all.

83.21.4. template_page

Not used in foundation catalog.

No Description.

83.21.5. comment

Example Data

   A must have for all painters!  This spackling knife is ergon...
   Enjoy the perfect feel and swing of our line of hammers. Thi...
   This set includes 2" and 3" trim brushes and our ergonomical...
   This set of disposable foam brushes is ideal for any stainin...

This is the field for a long description of the product. If you are using an Interchange text/gdbm database, the field size is unlimited; if using another type of database, the length will be dependent on the field type selected. If you are using a SQL database, see the appropriate cat_root/dbconf subdirectory for a place to set COLUMN_DEF values. See also the database documentation, 'Importing from an ASCII File', for details about defaults for columns that you do not define.

83.21.6. thumb

Example Data

   gift_certificate.gif
   os28004_b.gif
   os28005_b.gif
   os28006_b.gif

This is the filename for a small (thumbnail) image of the product.

83.21.7. image

Example Data

   gift_certificate_large.gif
   os28004.gif
   os28005.gif
   os28006.gif

This is the filename for a regular-sized image of the product, as it should appear in an HTML <img src="image"> tag. You do not need to specify the path if the image files are in the usual Interchange image directory.

83.21.8. price

Example Data

   1.00
   12.99
   14.99
   9.99

The quantity-one price of the product. See the wholesale field and the price table for dealer and quantity pricing.

83.21.9. wholesale

Example Data

   1
   10
   11
   12

This is the minimum dealer price for the item. For quantity pricing, see the price table.

83.21.10. prod_group

Example Data

   Hand Tools
   Hardware
   Ladders
   Measuring Tools
   Miscellaneous
   Painting Supplies
   Safety Equipment
   Tool Storage

Product group (supercategory). This indicates the grouping of product categories, for example in the navigation bars created from the area table (note the match with the name data in the area table).

83.21.11. category

Example Data

   Brushes
   Gift Certificate
   Hammers
   Ladders
   Nails
   Paintbrushes
   Putty Knives
   Rollers

This is the category the product should appear in when you select a list. You can put a product in more than one category, but you may need to accommodate this in display and banner headings. Embedded perl is helpful for this.

83.21.12. nontaxable

Boolean value. If true (1), the sales tax calculation for an order will not include the cost of the product. See also the salestax tag.

83.21.13. weight

Example Data

   1
   2
   3

This is a numeric value of the weight used for determining shipping costs (with UPS, for example). In the US, this is typically the weight in pounds in order to match the UPS, Fed Ex and other standard shipping tables.

83.21.14. size

Example Data

   1", 2", 3"
   1', 1.5'
   1/4", 1/2", 3/4", 1", 2", 3"
   10oz, 15oz, 20 oz
   2"
   6'
   set
   standard, metric

This is where the old Construct Something demo store kept the 'size' options for a product. The foundation catalog now uses the options table instead to handle product options (also sometimes called product attributes).

The accessories tag can build HTML widgets from the comma-delimited list of product options. You can use a delimiter other than comma (if compatible with the table) as long as you also set the delimiter in the accessories tag.

You probably do not need this field if you use the options table (for example, if you are building from the foundation catalog).

83.21.15. color

Another product option column. No longer used in the foundation catalog. See size above for description.

83.21.16. gift_cert

Boolean value. If true (1), specifies that this product is a gift certificate. See also the gift_certs table.

83.21.17. related

Used for displaying "upsells," opportunities to purchase an additional item when this one is purchased. Contains a comma-separated list of SKUs to be offered.

The foundation catalog now instead uses the upsell_to field of the merchandising table for upselling.

83.21.18. featured

Deprecated in favor of the merchandising table.

83.21.19. inactive

If true (1), renders the product inactive (i.e., it will not appear in the catalog).

83.21.20. url

Not Documented

83.22. route.txt

    code
    attach
    continue
    commit
    commit_tables
    counter
    credit_card
    cyber_mode
    email
    empty
    encrypt
    encrypt_program
    errors_to
    increment
    inline_profile
    individual_track
    individual_track_ext
    partial
    pgp_cc_key
    pgp_key
    profile
    receipt
    reply
    report
    rollback
    rollback_tables
    supplant
    track

83.23. salestax.asc

83.24. shipping.asc

Shipping methods table

83.25. state.txt

State/territory/county information

    code
    sorder
    country
    state
    name
    tax
    postcode
    shipmodes
    tax_name

83.26. transactions.txt

Each individual customer order has an entry in this table. The line items are not entered here, but in the orderline table.

See the page query/check_orders.html for how it can be used. See etc/report for how to add to it.

    code
    store_id
    order_number
    session
    username
    shipmode
    nitems
    subtotal
    shipping
    handling
    salestax
    total_cost
    fname
    lname
        Last Name
    company
    address1
    address2
        Address line 2
    city
    state
    zip
    country
    phone_day
        Daytime Phone
    phone_night
        Home Phone
    fax
    email
    b_fname
    b_lname
        Billing Last Name
    b_company
    b_address1
    b_address2
        Billing Address Line 2
    b_city
    b_state
        Billing State
    b_zip
        Billing Postcode
    b_country
        Billing Country
    b_phone
    order_date
    order_ymd
    order_wday
    payment_method
    po_number
    avs
    order_id
    update_date
    status
    affiliate
    campaign
    parent
    archived
    deleted
    complete
    comments

83.27. userdb.txt

The user database used for maintaining customer address information, account information, preferences, and more. See icdatabase for more information.

    username
    password
    acl
    mod_time
    s_nickname
    company
    fname
    lname
    address1
    address2
    address3
    city
    state
    zip
        Postcode
    country
        Country
    phone_day
    mv_shipmode
    b_nickname
    b_fname
    b_lname
    b_address1
    b_address2
    b_address3
    b_city
    b_state
    b_zip
    b_country
    b_phone
        Billing Phone
    mv_credit_card_type
    mv_credit_card_exp_month
    mv_credit_card_exp_year
    p_nickname
    email
    fax
    phone_night
    fax_order
        Payment method:
            (none) = Credit Card
            1 = Fax or Mail
            2 = Purchase order
            3 = COD
    address_book
    accounts
    preferences
    carts
    owner
    file_acl
    db_acl
    order_numbers
    email_copy
    mail_list
        Mailing lists the customer has joined:
            offer = Special offers
            newsletter = Newsletter
            alert = Alerts and Recalls
            upgrade = Upgrades
    project_id
    account_id
    order_dest
    credit_limit
    inactive
    dealer
        Dealer:
            (none) = No
            1 = Yes
    b_company
    feedback
        ???

83.28. variable.txt

Configuration database

    code
        Variable name
    Variable
    pref_group
        Preferences area

84. HTML Hypertext links

Normally, regular hypertext links are not used in Interchange pages. These kinds of links will not include the session ID. If the customer follows an external link back to the catalog, the list of products ordered so far will have been lost. The area tag is used to generate a hypertext link which includes a session ID.

Instead of:

   <A HREF="/cgi-bin/catlink/shirts">Shirts</A>

Use:

   <A HREF="[area shirts]">Shirts</A>

85. Images

Inline images are placed in Interchange pages in the normal fashion with <IMG SRC="URL">. But since Interchange pages are served by a CGI program, it will by default automatically rewrite relative image links as absolute ones based on the ImageDir and ImageDirSecure directives.

86. Browser Cookies

The Foundation store enables the Cookies directive so that users with cookie-capable browsers will retain session context. Then, standard HREF and Interchange page links can be intermixed without the fear of losing the shopping basket. Cookie capability is also required to use search caching, page caching, and statically generated pages. If the user's browser does not support cookies, the cache will be ignored.

If planning to use more than one host name within the same domain for naming purposes (perhaps a secure server and non-secure server), set the domain with the CookieDomain directive. This must contain at least two periods (.) as per the cookie specification, and must be located in the same server as the domain.

87. Dependencies in administration

In general, it's a good idea to leave fields empty if you don't want to use them, instead of removing them from the database altogether. That way nothing in the administration interface or the Foundation pages will break.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Interchange I18N Features

88. Internationalization

Interchange has a rich set of internationalization (I18N) features that allow conditional message display, differing price formats, different currency definitions, price factoring, sorting, and other settings. The definitions are maintained in the catalog.cfg file through the use of built-in POSIX support and Interchange's Locale directive. All settings are independent for each catalog and each user visiting that catalog, since customers can access the same catalog in an unlimited number of languages and currencies.

88.1. Configuring the Locale

It is recommended to use the ScratchDefault directive for setting the catalog's default locale:

   ScratchDefault mv_locale de_DE

88.2. Setting the Locale

The locale could be set to fr_FR (French for France) in one of two ways:

[setlocale locale=locale* currency=locale* persist=1*]

            Dollar Pricing:
        
            [setlocale en_US]
            [item-list]
            [item-code]: [item-price]<BR>
            [/item-list]
        
            Franc Pricing:
        
            [setlocale fr_FR]
            [item-list]
            [item-code]: [item-price]<BR>
            [/item-list]
        
            [comment] Return to the user's default locale [/comment]
            [setlocale]

[page process/locale/fr_FR/page/catalog]

[page process/locale/fr_FR/currency/en_US/page/catalog]

Once the locale is persistently set for a user, it is in effect for the duration of their session.

88.3. Interchange Locale Settings

The Locale directive has many possible settings that allow complete internationalization of page sets and currencies. The Locale directive is defined in a series of key/value pairs with a key that contains word characters only being followed by a value. The value must be enclosed in double quotes if it contains whitespace. In this example, the key is Value setting.

   Locale fr_FR "Value setting" "Configuration de valeur"
   Locale de_DE "Value setting" Werteinstellung

When accessed using the special tag [L]Value setting[/L], the value Configuration de valeur will be displayed only if the locale is set to fr_FR. If the locale is set to de_DE, the string Werteinstellung will be displayed. If it is neither, the default value of Value setting will be displayed.

The [L] and [/L] must be capitalized. This is done for speed of processing as well as easy differentiation in text.

Another, way to do this is right in the page. The [LC] ... [/LC] pragma pair permits specification of locale-dependent text.

 [LC]
           This is the default text.
   [fr_FR] Text for the fr_FR locale. [/fr_FR]
   [de_DE] Text for the de_DE locale. [/de_DE]
 [/LC]

You can also place an entirely new page in place of the default one if the locale key is defined. When a locale is in force, and a key named HTMLsuffix is set to that locale, Interchange first looks for a page with a suffix corresponding to the locale. For example:

<A HREF="[area index]">Catalog home page</A>

If a page index.html exists, it will be the default. If the current locale is fr_FR, a page "index.fr_FR" exists, and Locale looks like this:

   Locale fr_FR HTMLsuffix  .fr_FR

Then, the .fr_FR page will be used instead of the .html page. For a longer series of strings, the configuration file recognizes:

   Locale fr_FR <<EOF
   {
       "Value setting",
       "Configuration de valeur",

       "Search",
       "Recherche"
   }
   EOF

This example sets two string substitutions. As long as this is a valid Perl syntax describing a series of settings, the text will be matched. It can contain any arbitrary set of characters that don't contain [L] and [/L]. If using double quotes, string literals like \n and \t are recognized.

A database can also be used to set locale information. Locale information can be added to any database in the catalog.cfg file, and the values in it will overwrite previous settings. For more information, see LocaleDatabase. The [L]default text[/L] is set before any other page processing takes place. It is equivalent to the characters "default text" or the appropriate Locale translation for all intents and purposes. Interchange tags and Variable values can be embedded.

Because the [L] message [/L] substitution is done before any tag processing, the command [L][item-data table field][/L] will fail. There is an additional [loc] message [/loc] UserTag supplied with the distribution. It does the same thing as [L] [/L] except it is programmed after all tag substitution is done. See the interchange.cfg.dist file for the definition.


Note: Be careful when editing pages containing localization information. Even changing one character of the message can change the key value and invalidate the message for other languages. To prevent this, use:

   [L key]The default.[/L]

The key msg_key will then be used to index the message. This may be preferable for many applications.

A localize script is included with Interchange. It will parse files included on the command line and produce output that can be easily edited to produce localized information. Given an existing file, it will merge new information where appropriate.

88.4. Special Locale Keys for Price Representation

Interchange honors the standard POSIX keys:

   mon_decimal_point    or      decimal_point
   mon_thousands_sep    or      thousands_sep
   currency_symbol      or      int_currency_symbol
   frac_digits  or      p_cs_precedes

See the POSIX setlocale(3) man page for more information. These keys will be used for formatting prices and approximates the number format used in most countries. To set a custom price format, use these special keys:

price_picture

            Locale en_US price_picture "$ ###,###,###.##"
             Locale en_US mon_thousands_sep ,
             Locale en_US mon_decimal_point .
             Locale en_US p_cs_precedes     1
             Locale en_US currency_symbol   $
            Locale fr_FR price_picture "##.###,## fr"


IMPORTANT NOTE: The decimal point in use, set by mon_decimal_point, and the thousands separator, set by mon_thousands_sep must match the settings in the price_picture. The frac_digits setting is not used in this case. It is derived from the location of the decimal (if any).

             Locale fr_FR mon_thousands_sep .
             Locale fr_FR mon_decimal_point ,
             Locale fr_FR p_cs_precedes     0
             Locale fr_FR currency_symbol   fr

picture

88.5. Dynamic Locale Directive Changes

If a Locale key is set to correspond to an Interchange catalog.cfg directive, that value will be set when the locale is set.

PageDir

            # Establish the default at startup
            PageDir   english
            Locale fr_FR  PageDir  francais
            Locale en_US  PageDir  english

ImageDir

            # Establish the default at startup
            ImageDir   /images/english/
            Locale fr_FR  ImageDir   /images/francais/
            Locale en_US  ImageDir   /images/english/

ImageDirSecure

PriceField

            # Establish the default at startup
            PriceField    price
            Locale fr_FR  PriceField  prix


Note: If no Locale settings are present, the display will always be price, regardless of what was set in PriceField. Otherwise, it will match PriceField.

PriceDivide

            # Default at startup is 1 if not set
            # Franc is strong these days!
            Locale fr_FR  PriceDivide  .20

PriceCommas

            # Default at startup is Yes if not set
            PriceCommas  Yes
            Locale fr_FR  PriceCommas  0
            Locale en_US  PriceCommas  1

UseModifier

            # Default at startup is 1 if not set
            # Franc is strong these days!
            UseModifier format
            Locale fr_FR  UseModifier formats

PriceAdjustment

            # Default at startup
            PriceAdjustment  format
            Locale fr_FR  PriceAdjustment  formats

TaxShipping,SalesTax

DescriptionField

            # Establish the default at startup
            DescriptionField    description
            Locale fr_FR  DescriptionField desc_fr

The [locale] tag

88.6. Sorting Based on Locale

The Interchange [sort database:field] keys will use the LC_COLLATE setting for a locale provided that:

If this arbitrary database named letters:

   code        letter
   00-0011     f
   99-102      
   19-202      a

and this loop:

   [loop 19-202 00-0011 99-102]
   [sort letters:letter]
   [loop-data letters letter]   [loop-code]
   [/loop]

used the default C setting for LC_COLLATE, the following would be displayed:

   a  19-202
   f  00-0011
     99-102

If the proper LC_COLLATE settings for locale fr_FR were in effect, then the above would become:

   a  19-202
     99-102
   f  00-0011

88.7. Placing Locale Information in a Database

Interchange has the capability to read its locale information from a database, named with the LocaleDatabase directive. The database can be of any valid Interchange type. The locales are in columns, and the keys are in rows. For example, to set up price information:

   key                 en_US   fr_FR   de_DE
   PriceDivide         1       .1590   .58
   mon_decimal_point   .       ,       ,
   mon_thousands_sep   ,       .
   currency_symbol     $        frs    DM
   ps_cs_precedes      1       0       0

This would translate to the following:

   Locale en_US PriceDivide         1
   Locale en_US mon_decimal_point   .
   Locale en_US mon_thousands_sep   ,
   Locale en_US currency_symbol     $
   Locale en_US ps_cs_precedes      1

   Locale fr_FR PriceDivide         .1590
   Locale fr_FR mon_decimal_point   ,
   Locale fr_FR mon_thousands_sep   .
   Locale fr_FR currency_symbol     " frs"
   Locale fr_FR ps_cs_precedes      0

   Locale de_DE PriceDivide         .58
   Locale de_DE mon_decimal_point   ,
   Locale de_DE mon_thousands_sep   " "
   Locale de_DE currency_symbol     "DM "
   Locale de_DE ps_cs_precedes      1

These settings append and overwrite any that are set in the catalog configuration files, including any include files.

Important note: This information is only read during catalog configuration. It is not reasonable to access a database for translation or currency conversion in the normal course of events.


Copyright 2002-2004 Interchange Development Group. Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms of the GNU General Public License. line:

Interchange Programmer Reference

89. Introduction

Interchange is a highly-complex but very powerful web application server focused on ecommerce. It is built on the power of Perl, using many of its standard modules and capabilities while defining many more.

While Interchange focuses on e-commerce, it is really a general-purpose database access, retrieval, and templating systems. Besides online stores, here are some of the applications have been built on top of it:

    Auction
    Calendar
    Configuration management
    Content management
    Document archival and rental
    Guestbook
    Image archival and download
    Intranet
    MP3 jukebox
    Poll
    Quiz
    Software repository
    Web log

This reference attempts to illuminate the source code of Interchagne and how you can write Perl enhancements, gadgets, and applications that integrate with Interchange.

89.1. Software installation

To follow along, it is recommended you get the latest release of Interchange (5.0 as of this writing), unpack it from the tar file, and install it at a private directory. For the purposes of this document, it will be assumed that Interchange is installed at /usr/local/interchange and that the catalogs are installed at /usr/local/catalogs.

89.2. Software prerequisites

Interchange only requires a few added Perl modules, which can be installed by getting the Perl CPAN bundle Bundle::Interchange. Install that (usually as root) with:

        perl -MCPAN -e 'install Bundle::Interchange'

To get most of the modules Interchange can use:

        perl -MCPAN -e 'install Bundle::InterchangeKitchenSink'

89.3. Audience

This reference is not meant for casual users of Interchange. Though they might learn something from reading it, it would probably not do them much targeted good. A reasonable set of prerequisites to make reading this document profitable include:

Programming knowledge

A good knowledge of Perl or strong knowledge of other programming languages is needed.

Database knowledge

Interchange is all about databases, and a knowledge of the concepts of database programming and SQL is strongly recommended.

Networking knowledge

The more you know about networking and the web, the more comfortable you will be with this document.

UNIX knowledge

Almost all production Interchange servers are UNIX-based, so knowledge of that is helpful.

90. Overview of Interchange

Interchange is a daemon server, similar to a web server. Its entry point is usually talking to it over a socket via its own protocol. That socket can be either UNIX domain or INET domain, or an infinite number of either.

90.1. Catalogs

Interchange as a server dispatches connections to a catalog, an independently-configurable set of data and templates. These are for the most part completely independent of each other, though they inherit common global characteristics and settings. Almost all of those can be overridden by the catalog.

90.2. Hacking

Of course Interchange's source is completely open and available. You could, if you wished, hack on it all you wanted. However this is strongly discouraged, for the simple reason that you can override almost any behavior with configurations and tag definitions of your own. In fact, if you want to override a core routine you can even do that.

So if you are tempted to hack a routine in the core, simply override it with:

GlobalSub <<EOR
sub override_me {
        package Vend::Interpolate;
        sub shipping {
                your_code();
        }
}
EOR

90.3. ITL -- Interchange Tag Language

Interchange delivers its content by parsing templates that contain text and ITL, tags in the Interchange Tag Language.

ITL takes the form of HTML-like tags using [square brackets] as the tag introduction. Here is an ITL tag sequence:

        [if value name]
        Your name is [value name], in case you forgot.
        [/if]

The above will show the contents of the [if ...] [/if] container providing a non-blank, non-zero value is present in the user session.

ITL provides direct access to Perl via the ITL container tags [perl], [calc] and [calcn], and [mvasp]. This allows ITL like:

        [calc]
                my $out = '';
                if($Values->{name}) {
                        $out = "Your name is $Values->{name}, in case you forgot.";
                }
                return $out;
        [/calc]

The above is completely identical to the ITL-only snippet above in effect.

In addition, you can call defined ITL tags in your embedded Perl:

        [calc]
                my $out = '';
                my $name = $Tag->value('name');
                if($name) {
                        $out = "Your name is $Values->{name}, in case you forgot.";
                }
                return $out;
        [/calc]

Again, the result is identical to the previous two examples.

90.3.1. User Defined Tags

ITL is comprehensibly extensible. You can produce your own ITL tags that are fully as powerful as the ones supplied with the distribution. In fact they are indistinguishable, as you will see when you examine the code hierarchy.

These tags can use any Perl module, use external programs, or basically do most anything Perl can, providing you define them in the Global configuration. Tags defined in the Catalog configuration are restricted by Perl's standard Opcode and Safe facilities, though they can optionally be allowed global capability.

See the ictags manpage for complete information on ITL.

90.4. Talking to Interchange via socket

Interchange can run in any of several modes:

Foreground

The foreground, meaning the same Interchange server listens for connections and then runs the tasks those connections cause.

Forking mode

One master Interchange listens for connections, then forks instances to handle the tasks those connections cause. The forked instance terminates at the end of the task.

Prefork mode

Similar to the way Apache does, Interchange can fork off a number of instances that all listen to the sockets open for connections. The first one to answer gets the task, runs it, then returns to listen again. After MaxChildRequests requests, it dies and causes another new instance to take its place.

mod_perl mode

Interchange can be loaded into mod_perl. See the documentation in scripts/ic_mod_perl.PL for information.

SOAP mode

Interchange can listen to a socket designed to accept a SOAP connection -- those always run in prefork mode. This mode can co-exist with other modes, so the same Interchange server can serve both page and SOAP requests.

90.5. Talking to Interchange over the command line

Interchange starts its servers by being invoked from the command line. Other command line invocations can stop the server via signal, cause addition of additional catalogs to respond to, remove catalogs from the list to respond to, or cause execution of "cron" jobs.

90.6. Data structure overview

Interchange has three major data stuctures, which correspond to the master server, the catalog, and the user.

You can examine two of these structures by setting in interchange.cfg:

        DumpStructure  Yes

This will by default dump an interchange.structure file which shows the global configuration, and a CATALOGNAME.structure file in each catalog directory showing that catalog's configuration.

The third structure, the user data session, can be viewed with the following ITL placed in a page:

        <XMP>[dump]</XMP>

90.6.1. The Global configuration

This is held in a set of variables inhabiting the Global package. They define overall server behavior, and contain pointers to the catalog structures.

The Global configuration is defined in interchange.cfg and any files that it reads via include statements. The configuration is produced by parsing interchange.cfg with the routine Vend::Config::global_config.

Directives can be defined for parsing by the catalog configuration within the global configuration -- and they can be deleted as well.

The only way to define new global directives is via hacking the source. Luckily, this is just about never needed -- you can define settings for use by your programs in Variable or other repositories.

90.6.2. The Catalog configuration

Each Interchange catalog has its own configuration completely independent from others. It is basically produced from the file catalog.cfg in the directory defined as the base for the catalog. It is parsed by the subroutine Vend::Config::config.

We say basically, because there are many ways to alter catalog configuration. (CATNAME below refers to the name of the catalog being configured.)

ConfigAllBefore

Global catalog configuration preamble, affecting all catalogs, can be defined by the Global directive ConfigAllBefore. It defaults to catalog_before.cfg in the Interchange software directory (/usr/local/interchange).

LI1. CATNAME.before

An individual per-catalog preamble configuration is defined in $Global::ConfDir/CATNAME.before.

By default it would be /usr/local/interchange/etc/CATNAME.before.

CATNAME.site

A file in the catalog directory which is read before catalog.cfg. Deprecated.

catalog.cfg

The normal configuration file.

CATNAME.after

An individual per-catalog postamble configuration is defined in $Global::ConfDir/CATALOGNAME.after. This can be used to prevent user catalogs from doing unsafe things -- for instance enforcing the use of encryption, or preventing running in WideOpen mode.

By default it would be /usr/local/interchange/etc/CATALOGNAME.after.

ConfigAllAfter

Global catalog configuration postamble, affecting all catalogs, can be defined by the Global directive ConfigAllAfter. It defaults to catalog_after.cfg in the Interchange software directory (/usr/local/interchange).

command line

Any configuration passed on the command line at Interchange startup is applied last. For instance, to test out a catalog named foundation with a different invocation URL without having to alter the config files:

bin/interchange --foundation:VendURL=http://localhost/cgi-bin/found \

That will set the foundation catalog directive values VendURL, SecureURL, and RobotLimit, overriding any settings in the configuration files.

Tied configuration

Interchange has dynamic catalog configuration as well. See Programming Watch Points in catalog.cfg.

90.7. Session data structure

Each user session is a hash reference saved in some sort of data repository. By default it is file-based using the Storable manpage, but it can reside in any Interchange database type as well.

It is placed at the global variable location $Vend::Session, which for programming use in UserTag and GlobalSub routines is $Session (meaning $Vend::Interpolate::Session).

The structure is initialized when the session is created (or canceled by the user). The initial form is described in Vend::Session::init_session:

    $Vend::Session = {
                'ohost'         => $CGI::remote_addr,
                'arg'           => $Vend::Argument,
                'browser'       => $CGI::useragent,
                'referer'       => $CGI::referer,
                'scratch'       => { %{$Vend::Cfg->{ScratchDefault}} },
                'values'        => { %{$Vend::Cfg->{ValuesDefault}} },
                'carts'         => {main => []},
                'levies'        => {main => []},
    };

This structure is used as a repository for the transitory user session values like form values, scratch variable settings, payment transaction results, errors, and any other user-tied values. It is also possible to add code that can be run on a user-by-user basis with the Autoload, Filter, and Profile facilities.

91. Tour the source

Navigating the Interchange source requires a couple of clues. The main program invocation point is bin/interchange in the Interchange software directory.

91.1. From startup to serving content

Once Interchange is invoked, it does some basic program configuration at the top of that file. The types of available database facilities and modules are determined, and the base modules are brought in with "use" or "require". Execution by a non-root user ID is checked.

After the initial program configuration, execution goes to the main_loop() subroutine in bin/interchange. Some more initialization is done, then the command line options are parsed. Options mostly will set the program mode (i.e. start, stop, kill, test, cron, or other command line actions), but can also set Global and Catalog configuration values.

Once the options are parsed, Interchange will chdir() to the Interchange software directory (/usr/local/interchange) and run its global configuration. That means all file names passed to it during this phase are relative to that program root.

Part of global configuration is determination of the ITL tags that will be used by Interchange. By default, that is all files with appropriate extensions under the code directory. Sets of tags to be used can be set with the TagGroup and TagInclude directives.

Global configuration also includes specifying the catalogs that will be configured and loaded in the next phase. This is done via the Catalog directive. An important part of that directive is supplying the script parameter, which is used to initialize the pointer structure which will select the catalog based on the URL coming in.

After Global configuration, catalog configuration commences, via the ::config_named_catalog() routine, which calls Vend::Config::config(). Each catalog specified in the global configuration has a base directory. Interchange does a chdir() to that directory and parses the various configuration files, databases and specified command-line parameters.

After the catalog is configured, the database is opened to ensure that database table objects are initialized properly. It is then immediately closed.

The resulting Catalog configuration structure reference is then saved in $Global::Selector and $Global::SelectorAlias so that the calling URL can map to the proper catalog.

Once all configuration is done, Interchange determines the program mode. There are only two modes -- test and serve. The test mode simply exits the program at this point -- it is used to test validity of the configuration.

If the mode is serve, ::main_loop() calls Vend::Server::run_server(). Based on global configuration, one of the server modes discussed previously is initialized and Interchange starts listening on one or more sockets for a connection from a client. (This is not true for mod_perl mode -- Interchange simply exits at that point and the code is waiting for mod_perl to call it.)

While waiting for a connection, signals are disabled and handlers are set up for TERM, HUP, INT, USR1, and USR2. TERM and INT both cause the main server to exit; HUP signals Interchange to look for a reconfiguration event; and USR1 and USR2 are optionally used to keep track of how many servers are running.

NOTE: Because signals are not especially safe in Perl prior to 5.8.0, occasionally a core dump can occur on receipt of USR1 or USR2. This is especially true for BSD with its reentrant system calls. They can be disabled by setting MaxServers to 0 -- PreFork mode is strongly suggested if that is done.

Once a connection is received, the connector parameters are checked for security constraints and Vend::Server::connection() is called. It reads the input from the client and constructs the environment, %CGI::values array, and any passed entity like an HTTP POST or multipart form (for file upload). Those are stored and and object referring to them and containing the connection file handle is constructed. That object is passed to main::dispatch() for processing.

The main::dispatch() routine performs more transaction setup then determines the catalog that will process the request. It sets $Vend::Cfg to the preset configuration for that catalog, sets file permissions as appropriate, and the catalog's database is opened.

Once initialiation of the catalog configuraion is complete, user initialization begins. Interchange determines the user session ID, if any, and restores the user session from the session database or starts a new session as appropriate. Perl objects that will be used in the session are initialized or constructed, auto-login is run, and the locale is determined and set. After that, the URI path is parsed, Autoload and Filter routines are run.

Finally a transaction action is determined. The action is the first path component of the path passed to Interchange. The remainder is passed to the subroutine implementing the action, and may be used as default path information for content or for other purposes.

For example, if the catalog VendURL is /cgi-bin/foundation and the URI sent to Interchange is /cgi-bin/foundation/order/something/or/another, the action is order, and the path sent to the action routine is is something/or/another.

If the transaction action is not mapped via standard system actions defined in the variable %action, or in the ActionMap *global* or ActionMap directives, then the action path component is restored to the content path, and that page is served (order/something/or/another in the example above).

If the action is mapped, it is run. If it returns a true value, the page to be served is determined by the setting of $CGI::values::mv_nextpage. The action can produce send its own output and return a non-true value, in which case Interchange will terminate the transaction at that time.

After the action is run and/or content is served, Interchange runs AutoEnd, saves the user session, closes the catalog database, and finally main::dispatch() returns. The calling Vend::Server::connection() does some cleanup and returns to the server loop. If the server was forked for that transaction only, it sends a signal indicating it is done, cleans up PID files, and exits. If it is in the foreground or in PreFork mode, it scrubs the Vend:: and CGI:: namespaces and returns to waiting for the next connection.

91.2. Notes about databases

Interchange maintains objects for all of its database tables defined in Database. These can be of diverse SQL, DBM, and LDAP types.

When the database is initialized at catalog configuration time, the individual database tables may be opened depending on type. In general, SQL and LDAP types are always opened, and DBM types are not.

Opening a database table can be expensive in terms of CPU and IO time. So when the database is opened for a page transaction, Interchange creates a "dummy" table object that waits for a real access. Those objects are trivial to create, and a fast processor can create hundreds of thousands per second.

When access is made, the database table is really opened and the expensive initialization is done. This allows many tables to be ready for access while only the ones used take up CPU and IO time.

Copyright 2002-2004 Interchange Development Group. Freely redistributable under terms of the GNU General Public License. line:

Configuration Reference

92. Interchange Table Editor

Interchange has a powerful, highly-configurable table editor application implemented via its [table-editor] ... tag.

It is called in an Interchange page as simply as:

    [table-editor cgi=1]

Given that call, it reads the passed CGI query information and builds a table editor for an interchange table.

Each field within the table editor is completely configurable for HTML widget type, label, help links, and more. These configurations can be saved in the mv_metadata database, or can be specified in the table-editor tag call itself.

The table editor is portable. It will work with any DBI/SQL database, with LDAP databases, and with Interchange DBM and plain-file databases.

Much of the Interchange administrative user interface (UI) is built around the table editor.

Its features include:

Complete range of widgets and data filters

Interchange has 18 different HTML widget types with data filters to condition the data.

Link fields from any table

Though the table editor uses one table as its base, fields from other tables can be brought in, and entire sets of records relationally linked to the base record can be edited within the table editor.

Tabbed display

Interchange automatically builds a tabbed interface from your fields specification.

"Wizard" mode

The table editor has a "wizard" mode that can collect information for accomplishing installation or setup tasks, with Next, Back, Cancel and Finish modes.

Templatable setup

You can completely control the way the table editor displays the widgets without interfering with its functionality.

Complex data structures

Interchange can build arbitrarily-deep data structures from form input. The collected data is serialized with the equivalent of Perl's Data::Dumper and stored in a single database field.

92.1. Calling the table editor

In its simplest form, table-editor is called in an ITL page with:

    [table-editor table=products key=os28004][/table-editor]

That will edit the table products using its default configuration, for the SKU os28004.

If no metadata is defined for the table, all fields are edited. To limit it with the tag call:

    [table-editor
        table=products
        key=os28004
        fields="sku price description" ][/table-editor]

To specify that the field description should have a different widget type, height, and width, you can specify:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"
        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

If you do this with the default foundation demo catalog, you will see:

   SKU            __________________________________

   Product Price  __________

                  +---------------------------------------------+
                  |                                             |
   Short          |                                             |
   Description    |                                             |
                  |                                             |
                  +---------------------------------------------+

Note that the labels are pulled from the mv_metadata definition -- any attributes not specified in the options do that. You can override each in turn -- to change SKU to "Part Number" you can do:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"

        label.sku="Part number"

        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

To change the style of the label column, you can set the style information with:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"

        label_cell_style="font-weight: bold"

        label.sku="Part number"
        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

This should bold the label text.

These are just a few small examples. There are more than 150 options for table editor which we will discuss below.

92.2. Attributes and attribute quoting

The [table-editor] is capable of accepting a large number of attributes. It uses standard ITL tag quoting, explained in the Interchange Tag Reference.

You can quote with single-quote (<'>), double-quote ("), backtick (`), or pipe (|). Material placed in backticks is run through a safe Perl interpreter. In fact, it is the equivalent of using the [calc] [/calc] tag pair except that contained ITL tags are not interpolated.

Pipe-quoting has the attribute of stripping trailing and leading whitespace; it is often convenient when specifying JavaScript (which uses both single and double quotes frequently) in the various *_extra parameters.

92.3. Templating

The [table-editor] is templated on several levels. In the most basic use, where you rely on it to build the table rows, there is the row_template option. By default, it is:

   <td$opt->{label_cell_extra}>
     {BLABEL}{LABEL}{ELABEL}{META_STRING}
   </td>
   <td$opt->{data_cell_extra}>
     <table cellspacing=0 cellmargin=0 width="100%">
       <tr>
         <td$opt->{widget_cell_extra}>
           {WIDGET}
         </td>
         <td$opt->{help_cell_extra}>
            {TKEY}
            {HELP?}<i>{HELP}</i>{/HELP?}
            {HELP_URL?}<BR><A HREF="{HELP_URL}">help</A>{/HELP_URL?}
         </td>
       </tr>
     </table>
   </td>

The values of $opt->{*_cell_extra} are constructed from the *_cell_class,

  [table-editor
            table=products
            key=os28004
            label_cell_class=myclass
            label_cell_width=10%
            label_cell_valign=top
            label_cell_extra=|bgcolor="cyan"|
            ][/table-editor]

The values specified with {LABEL}, {WIDGET}, etc. are what are used to substitute the widget values constructed from the metadata. A perfectly functional template would be:

<td>{LABEL}</td><td>{WIDGET}</td>

That would show the label and widget without any help being shown (even if it is available) and using the default styles for at table data cell.

There is also the overall template, which is passed as the container text for [table-editor]. Something equivalent to the default can be achieved with:

{TOP_OF_FORM} {HIDDEN_FIELDS} <table> <tr> <td>&nbsp;</td> <td>{TOP_BUTTONS}</td> </tr> {:REST} <tr> <td>&nbsp;</td> <td>{BOTTOM_BUTTONS}</td> </tr> </table> {BOTTOM_OF_FORM}

There are two other templates -- the break_template and the combo_template. See "Templates".

92.4. Metadata

Interchange's foundation demonstration catalog and UI rely on a table named mv_metadata, which contains the definitions for table and field appearance. This table is supported with a table definition editor (pages/admin/db_metaconfig) and a field definition editor (pages/admin/meta_editor).

The mv_metadata table has the following fields:

code

The key for the table. Normally, it takes the form

    table::column

where table is the table the field is contained in, and column is the table column name. It can also take the forms:

    view::table::column::key
    view::table::column
    table::column::key

Each is checked in turn to see if it exists, then applied. If none of the above is found, then the field is displayed with a default widget (a text box with size 50).

type

The widget type. The following, at least, are supported:

Type Name Description
text Text entry The normal HTML text entry field.
textarea Textarea The normal HTML textarea entry for putting in multiple lines of data.
select Select box Also known as as a dropdown menu. Interchange has many ways to populate the options via automatic database lookup, and you can specify options to add or replace a lookup.
yesno Yes/No (Yes=1) A dropdown/select looking for a Yes (1) or No (0) answer.
noyes No/Yes (No=1) A dropdown/select looking for a Yes (0) or No (1) answer.
yesno radio Yes/No (radio) Same as the yesno widget except implmented with a radio box.
noyes radio No/Yes (radio) Same as the noyes widget except implmented with a radio box.
multiple Multiple Select A dropdown/select with SIZE greater than 1.
combo Combo Select A dropdown/select with a preceding text entry field that can add a new entry. Needs the nullselect filter; usually combined with a lookup.
reverse_combo Reverse Combo A dropdown/select with a following text entry field that can add a new entry. Needs the last_non_null filter; usually combined with a lookup.
move_combo Combo move A dropdown select that sends clicked items to a textarea.
display Text of option Displays the label (only) for a select/radio choice.
hidden_text Hidden (show text) Shows the value of a field and includes a hidden field to put the value in the form. Usually used when you want to display a key for a record but not give the opportunity to change it (and create a new record).
radio Radio box Select one of many options with a check box. Usually can be used instead of a select; can be grouped in matrices.
radio_nbsp Radio (nbsp) Select one of many options with a check box. Usually can be used instead of a select; can be grouped in matrices. This version puts no spaces in the outputted HTML, guaranteeing no wrap. (You can use the newer nowrap styles in CSS instead, often.)
checkbox Checkbox Select one or more options with a checkbox. Usually can be used instead of a multiple select.
check_nbsp Checkbox (nbsp) Select one or more options with a checkbox. Usually can be used instead of a multiple select. This version puts no spaces in the outputted HTML, guaranteeing no wrap. (You can use the newer nowrap styles in CSS instead, often.)
imagedir Image listing Shows a list of already existing images in a directory, with a link to a dialog to upload a new one.
imagehelper Image upload Combines input of an image name along with upload of the image.
date Date selector Selects a date, with optional time. Used in combination with the date_change filter.
value Value Simply shows the value of the field, with no widget to set it.
option_format Option formatter  
show Show all options Shows all options for a select/radio/checbox type input, without a widget to set the value.
uploadhelper File Uppload Puts the contents of a file upload in the named variable. Can be used as filter.widget="upload"

These widgets are implemented with the Vend::Form module, and are discussed in more detail later in this document.

width

The width of the widget. Meaningful in some way for most types.

height

In the field metadata, it is meaningful for textarea, multiple select types (including the combo widgets), and for groups of radio and checkboxes.

In the table metadata context, defines the number of rows that will be shown on the record select page before a "more" list will be built.

field

The fields for an options lookup query if more than one. Default is none -- the field in "lookup" is used.

db

The table to do the lookup query in. Default is the same table as the column is in.

name

The name of the generated HTML form element. Default is the same name as the column for the widget.

outboard

Catchall field used in several ways by different widgets. Normally used to specify a foreign key, it can also contain a directory name or other information needed for a widget.

options

Hard-coded options for the select, checkbox, and radio box widget types.

attribute

Not normally used for table editor. Used in Interchange in the context of an [item-list ...] for generating option names.

label

The label associated with the field for display in the table editor. In the below example, "Foo" is the label:

    Foo: <input type=text value="bar" size=30>

help

Inline help to be displayed in the table editor.

lookup

A field name to look up options in. Normally this would be the same field as the widget, to generate a list of unique values. The equivalent to the query:

  SELECT DISTINCT foo FROM table ORDER BY foo

is done.

filter

A filter which should be applied to the data coming from a widget before saving in the database. A few examples of the dozens of standard filters are:

There are many more filters, and it is easy to specify custom filters. See Interchange's filters documentation.

help_url

A URL for extended help on a field.

pre_filter

For advanced use only. Specifies a filter that is run on the data before it is used to set the widget value. Not normally used.

lookup_exclude

A regular expression that can exclude certain values from a lookup list.

prepend

append

Valuse that are prepended and appended to the widget HTML, perhaps to call an external formatter or tool.

display_filter

Not normally used.

default

The default value that should be given to a column when it is of length zero.

extended

The repository for the serialized extended values set in metadata.

92.5. Extended settings

Interchange's meta editors use the table editor's serialization capability to set many more than just the fields mentioned above. There are over 150 different metadata settings, and it would be impossible to have each occupy a field in a table.

Many of these settings can be passed in a CGI query string if the cgi=1 option is specified.

across

The number of label-widget pairs which should be placed on each table row. The default is 1. Not passable by CGI.

action

The Interchange form action to use for the generated form. In normal mode, the default is "set". In wizard mode, the default is "return". Not passable by CGI.

action_click

An mv_click action that should be run on the Wizard next function. The default is "ui_override_next", which is usually a no-op on most systems. Not passable by CGI.

all_errors

Specifies that all form field entries should be checked for errors and their label fields set to the CONTRAST setting if an error is found.

all_opts

An ITL tag option that specifies that the table-editor options should be retrieved from one source.

If the option is a HASH reference, it will be used directly as a structure that will set all options.

If it is a scalar value, it will be used as a key to select the mv_metadata record which contains the options.

append

Active for every column in ui_data_fields. A value containing HTML which should be appended to the widget HTML.

auto_secure

Instructs Interchange to build a write enable only for the tables, columns, and keys that are specified in the table-editor call. Note that you can allow unfettered writes by setting the scratch variable mv_data_enable, but that it is rarely right to do so.

This prevents people from hacking together a duplicate of the [table-editor] form and writing columns or records they shouldn't.

This option is automatically disabled if the cgi option is enabled. Still, you should pay attention to what you are allowing users to write to your database.

back_text

The text that should be used in the Wizard Back button. Automatially translated for locale.

bottom_buttons

Indicates that buttons should always be only on the bottom. Normally, [table-editor] provides a top row of buttons if more than four rows are in the table.

break_cell_extra

Extra HTML attributes for the table cell in the standard break_row template. You might pass a valign, align, class, or other attribute:

    break-cell-extra=|class="myclass"|

break_row_extra

Extra HTML attributes for the table row in the standard break_row template. You might pass a valign, align, class, or other attribute:

    break-row-extra=|class="myclass"|

break_template

The HTML template that is used to present a break row. Default is:

        <tr$opt->{break_row_extra>
                <td colspan=$span $opt->{break_cell_extra>&nbsp;</td>
        </tr>

cancel_button_style

The HTML style for the cancel button.

cancel_text

The text placed in the "Cancel" button in both editor and wizard mode. Default is "Cancel".

cell_span

The number of cells that are in the span of a normal widget-label pair. The default is two, which is appropriate for the label in one table cell and the widget in the other. If you have a row_template like:

        <td>{LABEL}</td><td> --&gt; </td><td>{WIDGET}</td>

you would want a cell_span of three. For the row_template

        <td align=left>
                <b>{LABEL}</b><br>
                {WIDGET}
        </td>

you would want a cell_span of 1.

This allows the formatter to build the right number of cells for spacers and whole_row templates.

cgi

Signifies that some options may come from the URL calling the page where the [table-editor] resides.

This allows a simple:

        [table-editor cgi=1][/table-editor]

to be active for any table and key that are called with a URL like:

  http://your.catalog.url/cat/admin/flex_editor?mv_data_table=products?item_id=1

The auto-secure option is turned off if this option is set, for it would then be possible for people to call a table and set their own security.

check

A hash option that is active for every field. Defines a profile check that should be run on the field before the record will be allowed to be set (or the wizard allowed to go to the Next option.

This call

        [table-editor
                table=products
                item_id="[cgi sku]"
                check.description=required
        ][/table-editor]

ensures that the description field will be non-blank and non-zero before the record is written.

Works in conjunction with the process_filter profile provided as a part of the UI. If using the table editor outside the province of the UI, you will need to make sure you get this profile included; it normally resides in lib/UI/profiles.

clear_image

In cases where the table-editor templates need a transparent image for display padding, can set the path where that image is. Default is bg.gif, which comes with the Interchange UI.

color_fail

The color to set failure messages to in HTML. Default Red.

color_success

The color to set success messages to in HTML. Default Green.

data_cell_class

data_cell_style

data_cell_valign

data_cell_width

data_cell_align

data_cell_extra

The settable parameters allowing change of the HTML appearance of the data cell in the standard [table-editor] presentation. The default is data_cell_class set to cdata.

The easiest thing to do to alter the look is define the CSS class for cdata how you want it. But you can individually set the width, style, and alignments; and you can attach scripting events or other CSS calls to the cell as well with data_cell_extra.

The following table-editor call:

        [table-editor
                table=products
                item_id="[cgi sku]"
                data_cell_class=newclass
                data_cell_style="color:red"
                data_cell_extra=|onMouseOver="alert('move that mouse!'"|
                data_cell_valign=top
        ][/table-editor]

will result in a templated row of:

        <td class=clabel>{LABEL}</td>
        <td class="myclass"
                style="color:red"
                valign="top"
                onMouseOver="alert('move that mouse!')">
                        {WIDGET}{HELP?}{HELP} ... (rest of template)
        </td>

database

A hash attribute with a key associated with every field. Specifies the database table that will be used for a lookup (if any).

default

A hash attribute with a key associated with every field. Specifies the default value that will be used in the field if none is found in the table or otherwise available via the default_ref.

This is only active if the defaults flag is set.

default_ref

The hash reference that is used to set the defaults for the fields if there is no data in the table for that row. Default is $Values, the Interchange values hash.

You can set this in options with:

        [table-editor default_ref=`$CGI`]

Note the backticks. This calls Perl, which returns the $CGI reference.

If you have previously collected some defaults in a scratch variable, you could use that with:

        [table-editor default_ref=`$Scratch->{myhash}`]

Not settable in metadata, and it *must* be a hash reference or there will be a fatal error.

This is only active if the defaults flag is set.

defaults

Allows defaults to be set from the default hash above. When used in combination with force_defaults=1 forces the passed defaults to override any data previously residing in the table record.

enctype

The encoding type for the form generated by [table-editor]. If the file_upload option is set, it defaults to multipart/form-data, otherwise uses the form default for the browser (which is normally application/x-www-form-urlencoded).

extra

A hash attribute with a key associated with every field. Specifies some extra HTML parameter(s) which will be attached to the widget for the field, based on the behavior of Vend::Form.

Normally used to pass an onChange or other scripting event.

field

A hash attribute with a key associated with every field. Specifies the fields to be used as a value-label pair for a lookup (if there is one). Works in conjunction with the lookup and database tags.

To build a list of products for selection by SKU in the foo widget, without having to use the SKU as the label, you can do:

  [table-editor
        foo.widget=select
        foo.lookup=1
        foo.database=products
        foo.field="sku,description"
  /]

Essentiallly the same as:

  [table-editor
        foo.widget=select
        foo.lookup_query="select sku,description from products order by description"
  /]

file_upload

Specifies that file upload should be enabled by changing the form encoding type. Forms using the imagehelper widget need this set.

filter

A hash attribute with a key associated with every field. Specifies a filter that will be applied to the widget result data before it is put in the database. To make sure that an integer value doesn't have extraneous whitespace that could cause an error, do:

  [table-editor
        foo.widget=text_5
        foo.label="Seconds before we should become impatient and beep"
        foo.filter=digits
  /]

Filters can be chained; they are the normal Interchange filters active in many situations.

Works in conjunction with the process_filter profile provided as a part of the UI. If using the table editor outside the province of the UI, you will need to make sure you get this profile included; it normally resides in lib/UI/profiles.

force_defaults

Causes the entries in the "defaults" hash to be used to set the initial value of fields, disabling the preference for data coming from an existing record in the database.

form_extra

Extra information (usually scripting event calls) for the form. For instance, if you are maintaining a series of event monitors in and want to make sure the user knows that some changes will be lost, you can set up a routine named check_change() in JavaScript. To check the change and ask for a confirmation before submission, you can do:

  <script>
  var changed = new Array;
  function is_changed (element) {
        if(element != undefined)
                changed[changed.length] = element.name;
  }

  function check_change () {
        if(changed.length > 0)
          return
                confirm('the ' + changed.join(',') + ' elements were changed. Continue?');
        return true;
  }
  </script>

  [table-editor
        foo.widget=text_50
        foo.label="Important stuff"
        foo.extra='onChange="is_changed(this)"
        form_extra='onSubmit="return check_change()"'
  /]

You could also pass style information if that is ever appropriate. For form name, action, and target,

form_name

The name of the form. Do not include the NAME= portion, that is provided. Results in outputted HTML of:

        <FORM ACTION="$opt->{form_action}" METHOD=POST NAME="$opt->{form_name}">

get

Sets the method for the form to GET -- the default is POST.

height

A hash attribute with a key associated with every field. Sets the height of the widget if that is appropriate -- for example, it sets the ROWS parameter of a TEXTAREA, the SIZE parameter of a SELECT, etc. Also acts on the combination widgets according to the behavior of Vend::Form.

If you want to set the height of a cell, you should use the *_extra parameters.

help

A hash attribute with a key associated with every field. Specifies inline help that should be shown in the right-hand (data) portion of a widget row.

help_anchor

Sets the text that is used to anchor the help_url link. Default is help. Can also be used to set an image if you want to use that instead:

  [table-editor
        table=products
        key=os28004
        help_anchor='<img src="question_mark.jpg" border=0>'
  /]

help_cell_class

help_cell_style

help_cell_valign

help_cell_width

help_cell_align

help_cell_extra

Sets the help cell attributes. See data_cell_extra.

help_url

A URL which leads to extended help on a field. For example:

  [table-editor
        table=products
        key=os28004
        widget.foo=text_50
        label.foo="Important stuff"
        help.foo="This is a complex field."
        help_anchor="Search for more help"
        help_url.foo="http://www.google.com/search?q=foo"
  /]

hidden

Allows setting of extra hidden variables in a form. This is a hash attribute, with one key for every hidden variable you need to set.

  [table-editor
        table=products
        key=os28004
        hidden.foo=bar
        hidden.buz=baz
  /]

The above will include

        <input type="hidden" name="foo" value="bar">
        <input type="hidden" name="buz" value="baz">

href

Sets the action for the form. By default it is VendURL/ui, which checks for authorization for setting table records. If the secure=1 parameter is set, SecureURL will be used instead. parameter is set, the SecureURL the default

include_before

include_form

inner_table_width

item_id

js_changed

keep_errors

label

label_cell_extra

label_cell_width

layer_panel_style

layer_tab_style

left_width

link_before

link_extra

link_fields

link_key

link_label

link_sort

link_table

link_template

link_view

lookup

lookup_query

mailto

message_label

meta

meta_anchor

meta_anchor_specific

meta_append

meta_class

meta_extra

meta_prepend

meta_style

method

mv_auto_export

mv_blob_field

mv_blob_label

mv_blob_nick

mv_blob_only

mv_blob_pointer

mv_blob_title

mv_cancelpage

Specifies the destination page if you hit the cancel-button.

mv_data_auto_number

mv_data_fields

mv_data_function

mv_data_table

mv_failpage

mv_nextpage

mv_prevpage

next_text

You can customize an alternative text for the OK/Next button.

Note! If your alternative text is long, and you get the text chopped, be sure to specify a wider button with the ok_button_style setting (eg. ok_button_style=|font-weight: bold; width: 80px; text-align: center|)

no_bottom

By default, form buttons are displayed at the top and bottom of the table. Specifying no_bottom=1 prevents the bottom set of buttons from being displayed.

     no_bottom=1

no_meta

no_table_meta

no_top

By default, form buttons are displayed at the top and bottom of the table. Specifying no_top=1 prevents the top set of buttons from being displayed.

     no_top=1

nodelete

noexport

nosave

notable

ok_button_style

options

orig_back_text

orig_cancel_text

outboard

override

panel_append

panel_height

Specifies the height of the data panels used in the tabbed diaplay. The default is 600.

    panel_height=600

panel_id

Specifies the prefix used to identify the panels used in the tabbed display. The default is mvpan.

    panel_id=mvpan

panel_prepend

panel_style

Specifies the CSS style applied to the data panels used in the tabbed display. The default is:

    font-family: sans-serif;
    font-size: smaller;
    padding: 0;
    border: 2px;
    border-color:#999999;
    border-style:outset;

panel_width

Specifiesthe width of the data panels used in the tabbed diaplay. The default is 800.

    panel_width=800

passed

pre_filter

prepend

promiscuous

reload

reparse

restrict_allow

row_template

save_meta

secure

show_reset

simple_row

start_at

start_at_index

tab_bgcolor_template

Controls the iteration over the range of bgcolor attributes of the tabs in the tabbed display. If tab_bgcolor_template="#xx0000" the tabs will be set to "#ff0000" "#ee0000", etc. The default is "#xxxxxx" and the values are set to "#ffffff" "#eeeeee",etc. This option allows one to specify a range of colored tabs.

    tab_bgcolor_template="#xx0000"

tab_height

Specifies the height of the tabs in the tabbed display. The default is 20px.

    tab_height=20

tab_horiz_offset

Specifies the number of pixels that additional rows of tabs are shifted to the right. The default is 10px.

    tab_horiz_offset=10

tab_style

Specifies the CSS style applied to the tabs in the tabbed display. The default is:

   text-align:center;
   font-family: sans-serif;
   line-height:150%;
   font-size: smaller;
   border:2px;
   border-color:#999999;
   border-style:outset;
   border-bottom-style:none;

tab_vert_offset

Specifies the number of pixels that additional rows of tabs are shifted upward. The default is 20px.

    tab_vert_offset=20

tab_width

Specifies the width of the tabs in the tabbed display. The default is 120px.

    tab_width=120

tabbed

This option specifies that the tabbed display mode is to be used. The tabbed=1 option displays sections as DHTML tabbed panels.

table

This option specifies the table as the source / destination of the form fields. The table is specified in the form: table=products.

table_width

td_extra

template

ui_blob_hidden

ui_blob_widget

ui_break_before

ui_break_before_label

ui_clone_id

ui_clone_tables

ui_data_fields

Specifies the database fields that a form collects. This is a quoted space delimited list of column names from the database table.

     ui_data_fields="field1 field2 field3"

ui_data_fields_all

ui_data_key_name

ui_display_only

A quoted space delimited list of fields to be displayed but not edited.

    ui_display_only="property_id"

ui_hide_key

Hides the key-field in the form. Remember that if you use the fields option, then you have to include the key-column in that list. Otherwise the form will fail to update the record.

ui_meta_specific

ui_meta_view

ui_new_item

ui_profile

ui_profile_success

ui_wizard_fields

Specifies the fields that a form collects in wizard mode.

     ui_wizard_fields="wiz_field1 wiz_field2 wiz_field3"

widget

widget_cell_extra

widgets_only

width

wizard

Specifies that the form collects data as session variables as opposed to database fields. Data fields are specified using the ui_wizard_fields option.

wizard_cancel

wizard_next


Copyright 2002-2004 Interchange Development Group. Freely redistributable under terms of the GNU General Public License. line:

Interchange Tags Reference

93. Interchange Tag Reference

Interchange functions are accessed via the Interchange Tag Language (ITL). The pages in a catalog may be mostly HTML, but they will use ITL tags to provide access to Interchange's functions. ITL is a superset of MML, or Minivend Markup Language. Minivend was the predecessor to Interchange.

These tags perform various display and modification operations for the user session. There nearly 100 standard predefined tags, and the UserTag facility allows you to create tags that perform your own functions and can be just as powerful as the built-in tags.

This document covers Interchange versions 4.7 through 4.9.

94. Tag Syntax

ITL tags are similar to HTML in syntax, in that they accept parameters or attributes and that there are both standalone and container tags.

We will call an attribute a parameter if it may be called positionally or if it must be included (see the parameter and attribute sections below).

A standalone tag has no ending element, e.g.:

    [value name]

This tag will insert the user's name, providing they have given it to you in a form. A container tag has both a beginning and an ending element, as in:

    [if value name]
    You have a name. It is [value name].
    [/if]

94.1. Standard Syntax

The most common syntax is to enclose the tag with its parameters and attributes in [square brackets]. If the tag has an end tag, the tag and its end tag will delimit contained body text:

  [tagname parameters attributes]Contained Body Text[/tagname]


Caveat -- macros: Some macros look like tags or end tags. For example, [/page] is a macro for </A>. This allows you to conveniently write [page href]Target[/page], but 'Target' is not treated as contained body text.


When using the [tagname ...] syntax, there must be no whitespace between the left bracket ('[') and the tagname.

If a tag name includes an underscore or dash, as in [item_list], a dash is just as appropriate (i.e. [item-list]). The two forms are interchangeable, except that an ending tag must match the tag (i.e., don't use [item-list] list [/item_list]).

94.2. HTML-Comment

ITL also allows you to use '<!--[' and ']-->' as interchangeable alternatives to plain square brackets: [tagname] and <!--[tagname]--> are equivalent.

This allows you make your raw tags appear as comments to HTML browsers or editors. You might want to do this if your editor has trouble with ITL tags when editing Interchange page templates, or alternatively, if you want to use one .html file both as an Interchange template and as a static page delivered directly by your web server, without Interchange processing.

To properly HTML-comment contained body text, place your comment-style brackets appropriately, for example:

 <!--[tagname] Contained Body Text [/tagname]-->

Note that you must include whitespace between the HTML comment delimiters and the square brackets if you wish to actually comment out tag output in the browser. For example, if [value name] expands to 'Bill':

 '<!--[value name]-->'  becomes  'Bill'
 '<!-- [value name] -->'  becomes  '<!-- Bill -->'

94.2.1. Technical notes

While '<!--[' and '[' are completely interchangeable, the Interchange parser does not replace ']-->' with ']' unless it also sees '<!--[' at least once somewhere on the page. (This is a small parsing speed optimization.)

See the Template Parsing Order appendix if you are modifying the special administrative interface pages and intend to use this syntax.

94.3. Named vs. Positional Parameters

There are two styles of supplying parameters to a tag: named and positional.

In the named style you supply a parameter name=value pair just as most HTML tags use:

    [value name="foo"]

The positional-style tag that accomplishes the same thing looks like this:

    [value foo]

The parameter name is the first positional parameter for the [value] tag. Some people find positional usage simpler for common tags, and Interchange interprets them somewhat faster. If you wish to avoid ambiguity you can always use named calling.

In most cases, tag parameters specified in the positional fashion work the same as named parameters. However, there are a few situations where you need to use named parameters:

  1. If you want to specify a parameter that comes positionally after a parameter that you want to omit, e.g. omit the first parameter but specify the second. The parser would have no way of knowing which is which, so you just specify the second by name. This is rare, though, because the first positional parameters are usually required for a given tag anyway.
  2. When there is some ambiguity as to which parameter is which, usually due to whitespace.
  3. When you need to use the output of a tag as the parameter or attribute for another tag.

94.3.1. Interpolating parameters

If you wish to use the value of a tag within a parameter of another tag, you cannot use a positional call. You must also double-quote the argument containing the tag you wish to have expanded. For example, this will not work:

    [page scan se=[scratch somevar]]

To get the output of the [scratch somevar] interpreted, you must place it within a named and quoted attribute:

    [page href=scan arg="se=[scratch somevar]"]

Note that the argument to href ('scan') did not need to be quoted; only the argument to arg, which contained a tag, needed the quotes.

94.4. Universal Attributes

Universal attributes apply to all tags, though each tag specifies its own default for the attribute. The code implementing universal attributes is external to the core routines that implement specific tags.

94.4.1. interpolate

This attribute behaves differently depending upon whether the tag is a container or standalone tag. A container tag is one which has an end tag, i.e. [tag] stuff [/tag]. A standalone tag has no end tag, as in [area href=somepage]. (Note that [page ...] and [order ..] are not container tags.)

For container tags (interpolated)

For standalone tags (reparsed)

(Note: The mixing of 'interpolate' and 'reparse' logic occurred because 'interpolate' already worked this way when 'reparse' was added to Interchange. This may be fixed in a later release...)

Most standalone tags are not reparsed by default (i.e., interpolate=0 by default). There are some exceptions, such as the [include] tag.

Interpolation example:

Assuming that name is 'Kilroy',

   [log interpolate=1][value name] was here[/log]
   [log interpolate=0][value name] was here[/log]

the first line logs 'Kilroy was here' to catalog_root/etc/log, while the second logs '[value name] was here'.

Reparsing example:

Suppose we set a scratch variable called 'now' as follows:

   [set name=now interpolate=0][time]%A, %B %d, %Y[/time][/set]

If today is Monday, January 1, 2001,

   [scratch name=now interpolate=0]
   [scratch name=now interpolate=1]

the first line yields

   [time]%A, %B %d, %Y[/time]

while the second yields

   Monday, January 1, 2001

94.4.2. reparse

If true ("reparse=1"), the server will process any tags in the text output by the reparsed tag.

Reparse applies only to container tags (those with an end tag). The interpolate attribute controls reparsing of the output of standalone tags (see above).

Most container tags will have their output re-parsed for more Interchange tags by default. If you wish to inhibit this behavior, you must explicitly set the attribute reparse to 0. Note that you will almost always want the default action. The only container ITL tag that doesn't have reparse set by default is [mvasp].

Example:

Assuming that name is 'Kilroy',

  1.   [perl reparse=0]
          my $tagname = 'value';
          return "[$tagname name] was here\n"
       [/perl]

  2.   [perl reparse=1]
          my $tagname = 'value';
          return "[$tagname name] was here\n"
       [/perl]

expands to

  1.   [value name] was here

  2.   Kilroy was here

94.4.3. send

Deprecated

94.5. Tag-specific Attributes

Each tag may accept additional named attributes which vary from tag to tag. Please see the entry for the tag in question for details about tag-specific attributes.

94.6. Attribute Arrays and Hashes

Some tags allow you to pass an array or hash as the value of an attribute. For an ordinary tag, the syntax is as follows:

    attribute.n=value

    attribute.hashkey=value

where n is an integer array index. Note that you cannot use both an array and a hash with the same attribute -- if you use attribute.n, you cannot also use attribute.key for the same attribute.

Here is an example of an attribute array:

    search.0="se=hammer
              fi=products
              sf=description"
    search.1="se=plutonium
              fi=products
              sf=comment"

The [page] tag, for example, treats a search specification array as a joined search, automatically adding the other relevant search fields, including the 'co=yes' to indicate a combined search (joined searches are described in the Interchange database documentation).

Note that it is up to the tag to handle an array or hash value properly. See the documentation for the specific tag before passing it an attribute array or hash value.

94.6.1. Perl calls

Before passing attributes to a tag, the Interchange parser would convert the above example to an anonymous array reference. It would use the resulting arrayref as the value for the 'search' attribute in this example.

If you were passing the above example directly to a tag routine within a [perl] block or a usertag, you must actually pass an anonymous array as the value of the attribute as follows:

    my $arrayref = [ "se=hammer/fi=products/sf=description",
                     "se=plutonium/fi=products/sf=description", ];

    $Tag->routine( { search => $arrayref, } );

Similarly to use a hash reference for the 'entry' attribute:

    my $hashref = { name   => "required",
                    date   => 'default="%B %d, %Y"', };

    $Tag->routine( { entry => $hashref } );

95. Looping tags and Sub-tags

Certain tags are not standalone; these are the ones that are interpreted as part of a surrounding looping tag like [loop], [item-list], [query], or [search-region].

PREFIX represents the prefix that is used in that looping tag. They are only interpreted within their container and only accept positional parameters. The default prefixes:

Tag Prefix Examples
[loop] loop [loop-code], [loop-field price], [loop-increment]
[item-list] item [item-code], [item-field price], [item-increment]
[search-list] item [item-code], [item-field price], [item-increment]
[query] sql [sql-code], [sql-field price], [sql-increment]

Sub-tag behavior is consistent among the looping tags. Subtags are parsed during evaluation of the enclosing loop, before any regular tags within the loop.

There are two types of looping lists: ARRAY and HASH.

An array list is the normal output of a [query], a search, or a [loop] tag. It returns from 1 to N return fields, defined in the mv_return_fields or rf variable or implicitly by means of a SQL field list. The two queries below are essentially identical:

    [query sql="select foo, bar from products"]
    [/query]

    [loop search="
                    ra=yes
                    fi=products
                    rf=foo,bar
    "]

Both will return an array of arrays consisting of the foo column and the bar column. The Perl data structure would look like:

    [
        ['foo0', 'bar0'],
        ['foo1', 'bar1'],
        ['foo2', 'bar2'],
        ['fooN', 'barN'],
    ]

A hash list is the normal output of the [item-list] tag. It returns the value of all return fields in an array of hashes. A normal [item-list] return might look like:

    [
        {
            code     => '99-102',
            quantity => 1,
            size     => 'XL',
            color    => 'blue',
            mv_ib    => 'products',
        },
        {
            code     => '00-341',
            quantity => 2,
            size     => undef,
            color    => undef,
            mv_ib    => 'products',
        },

    ]

You can also return hash lists in queries:

    [query sql="select foo, bar from products" type=hashref]
    [/query]

Now the data structure will look like:

    [
        { foo => 'foo0', bar => 'bar0' },
        { foo => 'foo1', bar => 'bar1' },
        { foo => 'foo2', bar => 'bar2' },
        { foo => 'fooN', bar => 'barN' },
    ]

95.1. PREFIX-accessories

   [PREFIX-accessories arglist]

Except for the usual differences that apply to all subtags (such as parsing order), these are more or less equivalent for an array-type list:

    [accessories code=current_item_code arg=arglist]
    [item-accessories arglist]

See the [accessories] tag for more detail. Note that you must use the comma-delimited list to set attributes -- you cannot set named attributes with the usual 'attribute=value' syntax.

If the list is a hash list, i.e. an [item-list], then the value of the current item hash is passed so that a value default can be established.

95.2. PREFIX-alternate

   [PREFIX-alternate N] DIVISIBLE [else] NOT DIVISIBLE [/else][/PREFIX-alternate]

Set up an alternation sequence. If the item-increment is divisible by `N', the text will be displayed. If an `[else]NOT DIVISIBLE TEXT[/else]' is present, then the NOT DIVISIBLE TEXT will be displayed.

For example:

    [item-alternate 2]EVEN[else]ODD[/else][/item-alternate]
    [item-alternate 3]BY 3[else]NOT by 3[/else][/item-alternate]

There are some additional primitives:

Tag Description
[item-alternate first_only] Only true on first item
[item-alternate last_only] Only true on last item
[item-alternate except_last] True except on last item
[item-alternate except_first] True except on last item
[item-alternate 0] Same as "first_only"
[item-alternate -1] Same as "except_last"

In the common case where you want to separate by a comma or other joiner:

        You have the following items:
        [item-list]
                [item-code][item-alternate except_last], [/item-alternate]
        [/item-list]

95.3. PREFIX-calc

   [PREFIX-calc] 2 + [item-field price] [/PREFIX-calc]

Executes Perl code in the tag body. This is equivalent to the [calc] ... [/calc] tag pair, except it's calculated at loop time instead of later when the rest of the page is parsed.

95.4. PREFIX-change

   [PREFIX-change][condition] ... [/condition] TEXT [/PREFIX-change]

Sets up a breaking sequence that occurs when the contents of [condition] [/condition] change. The most common one is a category break to nest or place headers.

The region is only output when a field or other repeating value between [condition] and [/condition] changes its value. This allows indented lists similar to database reports to be easily formatted. The repeating value must be a tag interpolated in the search process, such as [PREFIX-field] or [PREFIX-field database field]. If you need access to ITL tags, you can use [PREFIX-calc] with a $Tag-foo()> call.

Of course, this will only work as you expect when the search results are properly sorted.

The value to be tested is contained within a [condition]value[/condition] tag pair. The [PREFIX-change] tag also processes an [else] [/else] pair for output when the value does not change.

Here is a simple example for a search list that has a field category and subcategory associated with each item:

 <TABLE>
 <TR><TH>Category</TH><TH>Subcategory</TH><TH>Product</TH></TR>
 [search-list]
 <TR>
    <TD>
         [item-change cat]

         [condition][item-field category][/condition]

                 [item-field category]
         [else]
                 &nbsp;
         [/else]
         [/item-change cat]
    </TD>
    <TD>
         [item-change sub]

         [condition][item-field subcategory][/condition]

                 [item-field subcategory]
         [else]
                 &nbsp;
         [/else]
         [/item-change sub]
    </TD>
    <TD> [item-field name] </TD>
 [/search-list]
 </TABLE>

The above should put out a table that only shows the category and subcategory once, while showing the name for every product. (The &nbsp; will prevent blanked table cells if you use a border.)

95.5. PREFIX-code

   [PREFIX-code]

The key or code of the current loop. In an [item-list] this is always the product code; in a loop list it is the value of the current argument; in a search it is whatever you have defined as the first mv_return_field (rf).

95.6. PREFIX-data

   [PREFIX-data table field]

Calls the column field in database table table for the current [PREFIX-code] This may or may not be equivalent to [PREFIX-field field] depending upon whether your search table is defined as one of the ProductFiles.

95.7. PREFIX-description

   [PREFIX-description]

The description of the current item, as defined in the catalog.cfg directive DescriptionField. In the demo, it would be the value of the field description in the table products.

If the list is a hash list, and the lookup of DescriptionField fails, then the attribute description will be substituted. This is useful to supply shopping cart descriptions for on-the-fly items.

95.8. PREFIX-discount

   [PREFIX-discount]

The price of the current item is calculated, and the difference between that price and the list price (quantity one) price is output. This may have different behavior than you expect if you set the [discount] tag along with quantity pricing.

95.9. PREFIX-discount-subtotal

   [PREFIX-discount-subtotal]

Inserts the discounted subtotal of the ordered items.

95.10. PREFIX-field

   [PREFIX-field]

Looks up a field value for the current item in one of several places, in this order:

    1. The first ProductFiles entry.
    2. Additional ProductFiles in the order they occur.
    3. The attribute value for the item in a hash list.
    4. Blank

A common user error is to do this:

    [loop search="
                    fi=foo
                    se=bar
                "]

    [loop-field foo_field]
    [/loop]

In this case, you are searching the table foo for a string of bar. When it is found, you wish to display the value of foo_field. Unless foo is in ProductFiles and the code is not present in a previous product file, you will get a blank or some value you don't want. What you really want is [loop-data foo field], which specifically addresses the table foo. See also [PREFIX-param] and [PREFIX-pos].

95.11. PREFIX-increment

   [PREFIX-increment]

The current count on the list, starting from either 1 in a zero-anchored list like [loop] or [item-list], or from the match count in a search list.

If you skip items with [PREFIX-last] or [PREFIX-next], the count is NOT adjusted.

95.12. PREFIX-last

   [PREFIX-last] CONDITION [/PREFIX-last]

If CONDITION evaluates true (a non-whitespace value that is not specifically zero) then this will be the last item displayed.

95.13. PREFIX-line

   [PREFIX-line start_column]

Returns all array values from the current looping row in a single string, with each value separated by a tab, roughly equivalent to this:

  [PREFIX-pos 0](tab)[PREFIX-pos 1](tab)[PREFIX-pos 2](tab)[...]

for however many fields were returned in that row.

This is useful as a quick way to see all your results at a glance and verify your search specification.

If the optional start_column attribute is given, the output starts with that column instead of column 0.

95.14. PREFIX-modifier

   [PREFIX-modifier attribute]

If the item is a hash list (i.e. [item-list]), this will return the value of the attribute.

95.15. PREFIX-next

   [PREFIX-next] CONDITION [/PREFIX-next]

If CONDITION evaluates true (a non-whitespace value that is not specifically zero) then this item is skipped.

95.16. PREFIX-param

   [PREFIX-param name]

Returns the value of the column name associated with the looping tag row. Each looping list returns an array of return fields, set in searches with mv_return_field or rf. The default is only to return the code of the search result, but by setting those parameters you can return whichever columns you wish.

In a [query] ITL tag you can select multiple return fields with something like:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-code]  [prefix-param foo]  [prefix-param bar]
    [/query]

In this case, [prefix-code] and [prefix-param foo] are synonyms, as foo is the first returned parameter and becomes the code for this row. Another synonym is [prefix-pos 0].

Mixed case field names in your SQL tables will be forced to lower case in the [prefix-param name] tag if the underlying Database does that (as with most SQL types). For example if your query is

    [query prefix=prefix sql="select Foo, Bar from baz where Foo='buz'"]

then you must use:

    [prefix-param foo] and [prefix-param bar]

to display your results, rather than:

    [prefix-param Foo] and [prefix-param Bar]

Note that the following code is invalid:

    [query prefix=prefix sql=|
        SELECT  table1.foo,
                table2.bar
        FROM    table1, table2
        WHERE   table1.code = table2.code
        AND     table1.foo = 'buz'
    |]
        [prefix-param table1.foo] [prefix-param table2.bar]
    [/query]

The problem with the above code is that DBI doesn't support column names such as table1.foo in its resultsets. The following query syntax is fully supported by DBI and therefore by Interchange:

    [query prefix=prefix sql=|
        SELECT  table1.foo AS foo,
                table2.bar AS bar
        FROM    table1, table2
        WHERE   table1.code = table2.code
        AND     table1.foo = 'buz'
    |]
        [prefix-param foo] [prefix-param bar]
    [/query]

95.17. PREFIX-pos

   [PREFIX-pos N]

Returns the value of the array parameter associated with the looping tag row. Each looping list returns an array of return fields, set in searches with mv_return_field or rf. The default is only to return the code of the search result, but by setting those parameters you can return whichever columns you wish.

[PREFIX-pos N] outputs the data from the Nth column as returned (starting with zero). [PREFIX-param] lets you access the data by column name instead of by number.

In a [query ...] ITL tag you can select multiple return fields with something like:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-code]  [prefix-param foo]  [prefix-param bar]
    [/query]

In this case, [prefix-code] and [prefix-param foo] are synonyms, as foo is the first returned parameter and becomes the code for this row. Another synonym is [prefix-pos 0]. [prefix-pos 1] is the same as [prefix-param bar]. The following code will produce exactly the same output as the above:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-pos 0]  [prefix-pos 0]  [prefix-pos 1]
    [/query]

Note that if you use the [PREFIX-pos] tag, you may have to review your column numbers whenever you modify the columns you select. For this reason, queries that make use of the [PREFIX-param] tag may be easier to maintain and will be less prone to future surprises.

95.18. PREFIX-price

   [PREFIX-price]

The price of the product identified by the current code, formatted for currency. If Interchange's pricing routines cannot determine the price (i.e. it is not a valid product or on-the-fly item) then zero is returned. If the list is a hash list, the price will be modified by its quantity or other applicable attributes (like size in the demo).

95.19. PREFIX-quantity

   [PREFIX-quantity]

The value of the quantity attribute in a hash list. Most commonly used to display the quantity of an item in a shopping cart [item-list].

95.20. PREFIX-subtotal

   [PREFIX-subtotal]

The [PREFIX-quantity] times the [PREFIX-price]. This does take discounts into account.

95.21. if-PREFIX-data

   [if-PREFIX-data table field] IF text [else] ELSE text [/else] [/if-PREFIX-data]

Examines the data field, i.e. [PREFIX-data table field], and if it is non-blank and non-zero then the IF text will be returned. If it is false, i.e. blank or zero, the ELSE text will be returned to the page.

This is much more efficient than the otherwise equivalent [if type=data term=table::field::[PREFIX-code]].

You cannot place a condition; i.e. [if-PREFIX-data table field eq 'something']. Use [if type=data ...] for that.

Careful, a space is not a false value!

95.22. if-PREFIX-field

   [if-PREFIX-field field] IF text [else] ELSE text [/else] [/if-PREFIX-field]

Same as [if-PREFIX-data ...] except uses the same data rules as [PREFIX-field].

95.23. PREFIX-modifier-name

   [PREFIX-modifier-name attribute]

Outputs a variable name which will set an appropriate variable name for setting the attribute in a form (usually a shopping cart). Outputs for successive items in the list:

    1. attribute0
    2. attribute1
    3. attribute2

etc.

[PREFIX-modifier-name quantity] would be the same as [PREFIX-quantity-name].

95.24. PREFIX-quantity-name

   [item-quantity-name]

Outputs for successive items in the list:

    1. quantity0
    2. quantity1
    3. quantity2

etc.

[PREFIX-modifier-name quantity] would be the same as [PREFIX-quantity-name].

96. Tags

Each ITL tag is show below. Calling information is defined for the main tag, sub-tags are described in Looping tags and Sub-tags.

96.1. accessories

A Swiss-army-knife widget builder, this provides access to Interchange's product option attributes (e.g., to choose or access product options such as a shirt's size or color).

Can build selection objects (radio, check, select boxes, etc), forms or hyperlinks, or can simply return a value.

Or more -- see also Looping tags and Sub-tags.

96.1.1. Summary

    [accessories code arg]
    [accessories code=os28044 arg="size, radio, ... " other_named_attributes] deprecated
    [accessories code=os28044 attribute=size type=radio ... other_named_attributes]
Parameters Description Default
code Value of the master key in the product (or specified other) table none
arg Positionally interpreted comma-delimited list of values for the following attributes:
    "attribute, type, column, table, name, outboard, passed"
none
Attributes Default
attribute none
type
    One of select, value, text, textarea, hidden, password, combo, move_combo, reverse_combo, show, options, labels, checkbox, radio, links
select
column attribute
table products
name mv_order_attribute
outboard none
passed none
key (alias for code) none
row (alias for code) none
base (alias for table) products
database (alias for table) products
db (alias for table) products
col (alias for column attribute
field (alias for column attribute
delimiter comma (',')
prepend none
append none
extra none
js none
rows varies with type; often 4
cols varies with type; often 40
width none
default none
price none
price_data none
contains (type=radio or check) none
joiner (type=links) none
href (type=links) none
template (type=links) none
form (type=links) mv_action=return
empty (type=links) none
secure (type=links) none
new none
interpolate (reparse) No
Other_Characteristics  
Invalidates cache No
Container tag No
Has Subtags No

Tag expansion example:

    [accessories os28044 size]
---
    <SELECT NAME="mv_order_size"><OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz<OPTION VALUE="20oz">20oz</SELECT>

ASP-like Perl call:

    $Tag->accessories(  { code   => '[[EXAMPLE_SKU]]',
                          arg    => 'color, radio'
                          table  => 'special_products', }  );

or similarly with positional parameters,

    $Tag->accessories($code, $arg, $attribute_hash_reference);

96.1.1.1. See Also

Looping tags and Sub-tags.

96.1.2. Description

This is the swiss-army-knife widget builder for providing access to Interchange's product option attributes (e.g., to choose or access product options such as a shirt's size or color).

Interchange allows you to choose item attribute values for each ordered item -- you can attach a size, color, or other modifier to a line item in the shopping cart. You can also resubmit previous attribute values via hidden fields on a form.

The catalog.cfg file directive UseModifier is used to set the name of the modifier or modifiers. For example

    UseModifier        size color

will attach both a size and color attribute to each item code that is ordered.


Important Note -- You may not use the following names for attributes:

item group quantity code mv_ib mv_mi mv_si


You can also set modifier names with the mv_UseModifier scratch variable -- [set mv_UseModifier] size color [/set] has the same effect as above. This allows multiple options to be set for products. Whichever one is in effect at order time will be used. Be careful; you cannot set it more than once on the same page. Setting the mv_separate_items or global directive SeparateItems places each ordered item on a separate line, simplifying attribute handling. The scratch setting for mv_separate_items has the same effect.

The modifier value is accessed in the [item-list] loop with the [item-param attribute] tag, and form input fields are placed with the [modifier-name attribute] tag. This is similar to the way that quantity is handled.


Note: You must be sure that no fields in your forms have digits appended to their names if the variable is the same name as the attribute name you select, as the [PREFIX-modifier-name size] variables will be placed in the user session as the form variables size0, size1, size2, etc.


Interchange will automatically generate the select boxes when the [accessories code="os28044" attribute="size"] or [item-accessories size] tags are called. They have the syntax:

    [item-accessories attribute, type, column, table, name, outboard, passed]

    [accessories code=sku
                attribute=modifier
                type=select
                column=db_table_column_name
                table=db_table
                name=varname
                outboard=key
                passed="value=label, value2*, value3=label 3"]

    [accessories js=| onChange="set_description(simple_options, variant)"; |
                type=select
                name="[item-param o_group]"
                passed="=--choose--,[item-param o_value]"]


Notes:

  1. The 'attribute' attribute is required.
  2. See the type attribute for a list of types.
  3. The trailing '*' in value2 will mark it as the default ('SELECTED') value in the select widget (see below).


When called with an attribute, the database is consulted and looks for a comma-separated list of item attribute options. They take the form:

   name_a=Label Text1, default_name=Default Label Text*, name_b, etc.

The label text is optional -- if none is given, the name will be used (as in 'name_b' above).

If an asterisk is the last character of the label text, the item is the default selection. If no default is specified, the first will be the default. An example:

    [item-accessories color]

This will search the product database for a field named "color". If an entry "beige=Almond, gold=Harvest Gold, White*, green=Avocado" is found, a select box like this will be built:

    <SELECT NAME="mv_order_color">
    <OPTION VALUE="beige">Almond
    <OPTION VALUE="gold">Harvest Gold
    <OPTION SELECTED>White
    <OPTION VALUE="green">Avocado
    </SELECT>

In combination with the mv_order_item and mv_order_quantity session variables, you can use this to allow a customer to enter an item attribute during an order.

If used in an item list, and the user has changed the value, the generated select box will automatically retain the current value the user has selected.

The value can then be displayed with [item-modifier color] on the order report, order receipt, or any other page containing an [item-list].

96.1.2.1. Emulating with a loop

You can also build widgets directly, without using the accessories tag. You may have to do so if you need more control of the content than the tag offers. Below is a fragment from a shopping basket display form which shows a selectable size with "sticky" setting and a price that changes based upon the modifier setting. (Note that this example would normally be contained within the [item-list][/item-list] pair.)

    <SELECT NAME="[loop-modifier-name size]">
    [loop option="[loop-modifier-name size]" list="S, M, L, XL"]
    <OPTION> [loop-code] -- [price code="[item-code]" size="[loop-code]"]
    [/loop]
    </SELECT>

The output of the above would be similar to the output of [item-accessories size, select] if the product database field size contained the value S, M, L, XL. The difference is that the options in the loop emulation show the adjusted price in addition to the size within each option value.

96.1.2.2. Hash Lists -- Technical Note

As a technical note, some of the features of this tag work differently depending upon whether it was called with an '$item' hash reference, for example, as [item-accessories] within an [item-list].

In this context, the tag will have access to ancillary data from the item (including, perhaps, a user's chosen item attribute value). For example, if building a TEXTAREA widget within an [item-list], the widget will show the chosen item attribute value. On the other hand, within an array list such as a [search-list] in a [search-region], the widget would be empty.

If you really know what you're doing, you can pass it the item hash reference within a [perl] tag like this:

   $Tag->accessories( $code,
                      undef,              # 'arg' parameter value
                      $named_attribute_hashref,
                      $item_hashref );

See also Looping tags and Sub-tags for information about hash-context and array-context in looping tags.

96.1.2.3. code

This is the master key of the specified table (commonly sku in a product table). If no table is specified, the tag uses the products table by default.

You should not specify a code when looping on [item_accessories] because it internally sets 'code' to the key for the current item in the loop.

96.1.2.4. arg

Deprecated after Interchange 4.6

This allows you to pass values for some of the more commonly used attributes in the manner of the [item-accessories] tag, as a comma-delimited positional list:

  arg="attribute, type, column, table, name, outboard, passed"

Whitespace within the list is optional.

If you leave out one or more of the above attributes, be sure to keep the comma(s) if you are setting anything after it in the list:

  arg="attribute, type, , table"

The above examples show the attribute names for clarity; you would actually use the values. Hence, the previous example might actually be something like the following:

  arg="color, radio, , products"

Although you must use such a comma-delimited list to pass attributes to the [item-accessories] tag, please use named attributes instead for the [accessories] tag. The 'arg' attribute is deprecated.

For detail about a specific attribute, please see its subheading below.

96.1.2.5. attribute

Despite the name, this has nothing to do with tag attributes. You can set attributes for items in a database table (typically the products table) with the UseModifier configuration directive. Typical are size or color.

This selects the item attribute the tag will work with.

96.1.2.6. type

This determines the action to be taken. One of:

Action Description
select Builds a dropdown <SELECT> menu for the item attribute, with the default item attribute value SELECTED. The accessories tag builds a select widget by default if type is not set.
display Shows the label text for *only the selected option* if called in Hash List context (e.g., within an [item-list]). Ignored otherwise (i.e., the tag will build the default <SELECT> menu).
show Returns the list of possible attributes for the item (without labels or any HTML widget). For example, if sku os28044 is available in several sizes:
    [accessories os28044 size,show]
    -----------------------------------------
    Sm=10oz, Med=15oz*, Lg=20oz
options This shows the attribute options as a newline delimited list:
    [accessories os28044 size,options]
    -----------------------------------------
    Sm
    Med
    Lg
labels This shows the attribute option labels:
    [accessories os28044 size,options]
    -----------------------------------------
    10oz
    15oz*
    20oz
radio Builds a radio box group for the item, with spaces separating the elements.
radio nbsp Builds a radio box group for the item, with &nbsp; separating the elements.
radio break Builds a radio box group for the item, with '<br>' separating the radio button/label pairs from one another.
radio left n Builds a radio box group for the item, inside a table, with the checkbox on the left side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.

You can also set FONT SIZE like this:

  type="radio left n fontsizem"

where -9 <= m <= 9

radio right n Builds a radio box group for the item, inside a table, with the checkbox on the right side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.

You can also set FONT SIZE like this:

  type="radio right n fontsizem"

where -9 <= m <= 9

check Builds a checkbox group for the item, with spaces separating the elements.
check nbsp Builds a checkbox group for the item, with '&nbsp;' separating the checkbox/label pairs from one another.
check break Builds a checkbox group for the item, with '<br>' separating the checkbox/label pairs from one another.
check left n Builds a checkbox group for the item, inside a table, with the checkbox on the left side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.

You can also set FONT SIZE like this:

  type="check left n fontsizem"

where -9 <= m <= 9

check right n Builds a checkbox group for the item, inside a table, with the checkbox on the right side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.

You can also set FONT SIZE like this:

  type="check right n fontsizem"

where -9 <= m <= 9

textarea_XX_YY A textarea with XX columns and YY rows. The textarea will contain the selected item attribute value if used in Hash List context (e.g., within an [item-list]).

If you simply use 'type=textarea', the size will default to 4 rows by 40 columns, unless you have set the rows or cols tag attributes.

text_YY A text box with YY width in characters. The HTML tag's VALUE will be set to the selected item attribute value if used in Hash List context (e.g., within an [item-list]).

If you simply use 'type=text', the width will default to 60, unless you have set the cols tag attribute.

combo Special type, used with nullselect filter, for selecting from a list or inputting a new value
reverse_combo Special type, used with last_non_null filter, for selecting from a list or inputting a new value -- differs from combo in order of presentation
move_combo Special type, used with null_to_space or null_to_comma filter, for selecting multiple non-ordered values from a list or inputting into a textarea
links Produces a series of links based on the option values. The base form value is passed via the form parameter, just like in an [area ...] or [page ...] tag, and the value is named with the passed NAME attribute.
value Returns the selected value if called in Hash List context (e.g., within an [item-list]), or nothing otherwise.
hidden Creates a hidden form field. The hidden field's VALUE will be set to the selected item attribute value if used in Hash List context (e.g., within an [item-list]).
password_YY A password box with YY width in characters. The HTML tag's VALUE will be set to the selected item attribute value if used in Hash List context (e.g., within an [item-list]).

If you simply use 'type=password', the width will default to 12, unless you have set the cols tag attribute.

The default is 'select', which builds an HTML select form entry for the attribute.

Some types build widgets that use the ROWS=m, COLS=n, or certain other HTML attributes. For these, you can define widget rows and columns within the string that sets the type; for example, type="textarea_6_33_wrap=virtual" specifies a TEXTAREA widget with ROWS=6, COLS=33, and WRAP=virtual. You should resort to this only when you cannot use the named parameters, for example within an [item-accessories] tag. Otherwise, use the rows=m and cols=n tag attributes instead.

The result of setting conflicting values in the type string and the rows or cols attributes is undefined.

The following list shows syntax for type strings, where rows is the number of rows and cols is the number of columns.

In any of the option building types, you can append the string ranges and a special option processing will be done -- any option matching the pattern [A-Za-z0-0]..[A-Za-z0-0] will be expanded into a comma separated range between the bounds. The same behavior is accomplished by passing the accessories tag option ranges. For example:


    [accessories name=foo type=select ranges=1 "A..C,1..5,10,20"]
      and
    [accessories name=foo type="select ranges" passed="A..C,1..5,10,20"]

      will both output:

    <select NAME="foo">
    <option VALUE="A">A
    <option VALUE="B">B
    <option VALUE="C">C
    <option VALUE="1">1
    <option VALUE="2">2
    <option VALUE="3">3
    <option VALUE="4">4
    <option VALUE="5">5
    <option VALUE="10">10
    <option VALUE="15">15
    <option VALUE="20">20
    </select>

The above applies to any of the option building types -- check, combo, combo_move, labels, multiple, options, radio, reverse_combo, and select. It will refuse to produce more than 5000 options -- that limit can be changed with Limit option_list N in catalog.cfg, where N is an integer greater than 0.

96.1.2.7. column

The column of the table corresponding to the attribute will traditionally have the same name as the attribute, though it need not.

This specifies the table column that contains an item's attribute values. The tag will find item attribute names and values in a comma-delimited list of name=value pairs stored in this field of an item's table entry. If unspecified, the column name will default to the name given for the 'attribute' attribute.

For example, if an item in the products table has a 'size' attribute, and each item's comma-delimited list of available sizes is stored in the 'how_big' column, then you would need to specify "column=how_big" because the tag's default column choice (size) would be missing or used for some other purpose.

96.1.2.8. table

This is the database table containing the item's attribute values. It defaults to the first products file where the item code is found.

If you have configured your database so that the attributes are kept in a different table from other item data, 'code' should be set to the master key in this table. See 'outboard') if you are using [item-accessories] and cannot specify code=key.

96.1.2.9. name

This sets the name of the form variable to use if appropriate for the widget being built. Defaults to 'mv_order_attribute' -- i.e. if the attribute is size, the form variable will be named mv_order_size.

If the variable is set in the user session, the widget will "remember" its previous setting. In other words, [value name] will contain the previous setting, which the widget will use as its default setting. See also the default attribute.

96.1.2.10. outboard

If calling the item-accessories tag, and you wish to select from an outboard database table whose master key is different from the item code, you can pass the key the tag should use to find the accessory data.

96.1.2.11. passed

You can use this to pass your own values to the widget the tag will build. If you have set passed to a list of widget options, then the tag will simply build a widget of the specified type with your values instead of fetching an attribute value list from the database.

For example, to generate a select box with a blank option (perhaps forcing a select), the value of blue with a label of Blue, and the value of green with a label of Sea Green, do:

    [accessories type=select
                 name=color
               passed="=--select--*, blue=Blue, green=Sea Green"]

This will generate:

    <SELECT NAME="color"><OPTION VALUE="" SELECTED>--select--\
    <OPTION VALUE="blue">Blue\
    <OPTION VALUE="green">Sea Green</SELECT>

Note: trailing backslashes ('\') in the above example indicate line continuation and are not part of the tag output.

96.1.2.12. delimiter

The list of attribute values will be a delimited string. This allows you to specify an alternative delimiter if the list is not comma-delimited (the default).

96.1.2.13. prepend

You can set a string to prepend to the returned output of the tag. Note that this is not a list to prepend to the fetched attribute value list, which is treated within the tag.

For example,

    [accessories code=os28044
                 type=select
            attribute=size
               append="Append Me<br>"
              prepend="Prepend Me"]
---
    Prepend Me<SELECT NAME="mv_order_size">\
    <OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz\
    <OPTION VALUE="20oz">20oz</SELECT>Append Me<br>

96.1.2.14. append

You can set a string to append to the returned output of the tag. Note that this is not a list to append to the fetched attribute value list, which is treated within the tag.

96.1.2.15. extra

Setting the 'extra' attribute appends its value as the last attribute of the HTML output tag. The following example illustrates the append, extra and js options:

    [accessories code=os28044
                 type=select
            attribute=size
               append="Append Me<br>"
                extra="Last=Extra"
                   js="javascript_here"]
---
    <SELECT NAME="mv_order_size" javascript_here Last=Extra>\
    <OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz\
    <OPTION VALUE="20oz">20oz</SELECT>Append Me<br>

96.1.2.16. js

This allows you to place javascript within the start tag of the HTML output. See the example given above for extra.

js has no default, except when 'type=move_combo', where the default is:

  onChange="addItem(this.form.Xname,this.form.name)"

96.1.2.17. rows

The tag will pass the number you choose through to the HTML 'ROWS=n' attribute in HTML widgets that accept it.

For some types, you can also define widget rows and columns within the string that sets the type; for example, type="textarea_6_33_wrap=virtual" specifies a TEXTAREA widget with ROWS=6, COLS=33, and WRAP=virtual. You should resort to this only when you cannot use the named parameters, for example within an [item-accessories] tag.

The result of setting conflicting values in the type string and the rows=n attribute is undefined.

96.1.2.18. cols

The tag will pass the number you choose through to the HTML 'COLS=n' attribute in HTML widgets that accept it.

See also 'rows' above.

96.1.2.19. width

This is a quasi-alias for 'cols' that only works with the 'text' and '<password>' types. Use 'cols' instead.

96.1.2.20. default

Sets the default attribute option in the widget returned by the tag. This will override a default indicated with a trailing '*' in the database or 'passed' string. This will also override the default of a user's previous selection when the tag would otherwise have preserved it.

For example the following selects blue by default rather than green as it would otherwise have done,

    [accessories type=select
                 name=color
               passed="blue=blue, green=Sea Green*"
              default="blue"]
---
    <SELECT NAME="color"><OPTION VALUE="blue" SELECTED>blue\
    <OPTION VALUE="green">Sea Green</SELECT>
---

Obscure technical note: the tag ignores the 'default' attribute if it has an item hash reference -- see Hash Lists above.

96.1.2.21. price

When combined with the price_data tag attribute, this allows you to force prices for item attributes. You probably do not want to use this; just let the tag pick up prices from your database table(s) when appropriate.

If you are passing attribute values, you can use this to control the displayed price in the widget.

    [accessories type=check
                 name=color
                price=1
           price_data="blue=20, green=50"
               passed="blue=Blue, green=Sea Green*"]
---
    <INPUT TYPE="checkbox" NAME="color"
               VALUE="blue" >&nbsp;Blue&nbsp;($20.00)
    <INPUT TYPE="checkbox" NAME="color"
                   VALUE="green" CHECKED>&nbsp;Sea Green&nbsp;($50.00)

96.1.2.22. price_data

96.1.2.23. contains

Requires 'type=radio' or 'type=check'.

Used to determine whether a substring match of the value will cause a radio box or check box to be selected. If true, the match will happen whether the value is on a word boundary or not -- if false, the value must be on a word boundary. (When we speak of a word boundary, it is in the Perl sense -- a word character [A-Za-z0-9_] followed or preceded by a non-word character, or beginning or end of the string.)

96.1.2.24. joiner

Requires 'type=links'.

With type=links, the accessories tag returns a link for each option. This allows you to override the default string ('<BR>') that joins these links. You can use Perl's metacharacter escapes, such as '\n' for newline or '\t' for tab.

96.1.2.25. href

Requires 'type=links'.

This sets the base HREF for the link in a links type. Default is the current page.

96.1.2.26. template

Requires 'type=links'.

Allows you to override the standard Interchange template for a hyperlink. You probably don't need to use this -- grep the code to grok it if you do (see 'sub build_accessory_links').

96.1.2.27. form

Requires 'type=links'.

This sets the base value for the form in a links type. Default is mv_action=return, which will simply set the variable value in the link.

For example, to generate a series of links -- one per item attribute value passed -- that set the variable "color" to the corresponding passed value (blank, blue, or green), do this:

    [accessories type=links
                 name=color
               passed="=--select--, blue=Blue, green=Sea Green"]

This will generate something like the following:

    <A HREF="VENDURL/MV_PAGE?mv_action=return&color=blue">Blue</A><BR>
    <A HREF="VENDURL/MV_PAGE?mv_action=return&color=green">Sea Green</A>

where VENDURL is your Interchange URL for the catalog MV_PAGE is the current page.

If you want the empty "--select--" option to show up, pass an empty=1 parameter.

96.1.2.28. empty

Requires 'type=links'.

Setting 'empty=1' includes a hyperlink for the empty "--select--" option. See the example in form above; if empty=1 had been specified, three links would have been generated.

96.1.2.29. secure

Requires 'type=links'.

Setting secure=1 causes the generated link(s) to point to your secure Interchange URL.

96.1.2.30. new

Requires 'type=combo' or 'reverse_combo'.

You can use this to set a value in place of the 'New' or 'Current' option in a combo box. For example, if item 'os28044' has size attribute values of "Sm=10oz, Med=15oz, Lg=20oz":

    [accessories code=os28044 attribute=size type=combo new="my_new_value"]
---
    <INPUT TYPE=text NAME="mv_order_size" SIZE=16 VALUE="">
    <SELECT NAME="mv_order_size" SIZE="1">
    <OPTION VALUE="my_new_value">my_new_value
    <OPTION VALUE="Sm">10oz
    <OPTION VALUE="Med">15oz
    <OPTION VALUE="Lg">20oz</SELECT>

Or, with the default new value:

    [accessories code=os28044 attribute=size type=combo]
---
    <INPUT TYPE=text NAME="mv_order_size" SIZE=16 VALUE="">
    <SELECT NAME="mv_order_size" SIZE="1">
    <OPTION VALUE="">&lt;-- New
    <OPTION VALUE="Sm">10oz
    <OPTION VALUE="Med">15oz
    <OPTION VALUE="Lg">20oz</SELECT>

Default is no VALUE with option text set to '&lt;-- New' for a combo box or 'Current --&gt;' for a reverse_combo box.

96.2. and

96.2.1. Summary

Parameters: type term op compare

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no


Note: This tag has special positional parameter handling.

    [and type term op compare]
Parameters Description Default
base Alias for type DEFAULT_VALUE
comp Alias for compare DEFAULT_VALUE
compare   DEFAULT_VALUE
op   DEFAULT_VALUE
operator Alias for op DEFAULT_VALUE
term   DEFAULT_VALUE
type   DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache no
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [value name=fname set="Mike" hide=1]
    [value name=lname set="" hide=1]

    ...

    [if value fname]
    [and value lname]
        Both first and last name are present.
    [else]
        Missing one of "fname" and "lname" from $Values.
    [/else]
    [/if]
---
    Missing one of "fname" and "lname" from $Values.

ASP-like Perl call:

Not applicable. The [and ...] tag only is used with [if ...], and Perl logic obviates the [if ...] tag.

96.2.2. Description

The [and ...] tag is only used in conjunction with [if ...]. Example:

        [if value fname]
        [and value lname]
        Both first and last name are present.
        [else]
        Missing one of "fname" and "lname" from $Values.
        [/else]
        [/if]

See the description of the [if] tag.

96.2.2.1. compare

96.2.2.2. op

96.2.2.3. term

96.2.2.4. type

96.3. area

Alias: href

Expands to the URL for an Interchange page or action, including the Interchange session ID and supplied arguments. This is very similar to the page tag -- these are equivalent:

    [page href=dir/page arg=mv_arg]TargetName</A>
    <A HREF="[area href=dir/page arg=mv_arg]">TargetName</A>

96.3.1. Summary

    [area href arg]
    [area href=dir/page arg=page_arguments other_named_attributes]
Parameters Description Default
href Path to Interchange page or action
    Special arguments
    • 'scan' links to a search (using search arguments in arg)
    • 'http://...' external link (requires form attribute)
process
arg Interchange arguments to page or action none
Attributes Default
form none
search No
secure No
interpolate (reparse) No
Other_Characteristics  
Invalidates cache No
Macro No
Has end tag No

Tag expansion example:

    [area href=dir/page.html arg="arg1=AA/arg2=BB"]

    www.here.com/cgi-bin/mycatalog/page.html?mv_session_id=6CZ2whqo&\
    mv_pc=1&mv_arg=arg1%3dAA/arg2%3dBB

ASP-like Perl call:

    $Tag->area(  { href => "dir/page",
                   arg  => "arguments", }  );

or similarly with positional parameters,

    $Tag->area($href, $arg, $attribute_hash_reference);

96.3.1.1. See Also

page

96.3.2. Description

The area tag is very similar to the [page] tag. It produces the URL to call an Interchange page, but it differs from page in that it does not supply the surrounding <A HREF ...> notation. This can be used to get control of your HREF items, perhaps to place an ALT string or a Javascript construct.

It was originally named area because it also can be used in a client-side image map.

The area tag has an alias of href. The two links below are identical in operation:

   <A HREF="[area href=catalog]" ALT="Main catalog page">Catalog Home</A>
   <A HREF="[href href=catalog]" ALT="Main catalog page">Catalog Home</A>

The optional arg is used just as in the page tag.

96.3.2.1. form

The optional form argument allows you to encode a form in the link.

   <A HREF="[area form="mv_order_item=os28044
                        mv_order_size=15oz
                        mv_order_quantity=1
                        mv_separate_items=1
                        mv_todo=refresh"]"> Order 15oz Framing Hammer</A>

See the description of the [page] tag for more detail.

96.3.2.2. search

Interchange allows you to pass a search in a URL. There are two ways to do this:

  1. Place the search specification in the named search attribute.
    • Interchange will ignore the href parameter (the link will be set to 'scan'.
    • If you give the arg parameter a value, that value will be available as [value mv_arg] within the search display page.
  2. Set the href parameter to 'scan' and set arg to the search specification.
    • Note that you can use this form positionally -- the values go into href and arg, so you do not have to name parameters.

These are identical:

   <A HREF="[area scan
                  se=Impressionists
                  sf=category]">Impressionist Paintings</A>

   <A HREF="[area href=scan
                   arg="se=Impressionists
                        sf=category"]">Impressionist Paintings</A>

   <A HREF="[area search="se=Impressionists
                          sf=category"]">Impressionist Paintings</A>

See the description of the page tag for more detail.

96.3.2.3. secure

96.3.2.4. Examples

Tag expansion example:

    [area href=dir/page.html arg="arg1=AA/arg2=BB"]

    www.here.com/cgi-bin/mycatalog/page.html?mv_session_id=6CZ2whqo&\
    mv_pc=1&mv_arg=arg1%3dAA/arg2%3dBB

Positional call example:

    <A HREF="[area ord/basket]">Check basket</A>

Named call example:

    <A HREF="[area ord/basket]">Check basket</A>

96.4. assign

Allows you to assign numeric values to preempt calculation of one or more of the following tags:

[handling], [salestax], [shipping], and [subtotal]

The assignment is persistent within a user's session until you clear it, an assigned tag will return your value instead of calculating a value.

Warning -- please be sure you understand the dependencies within the pricing system before using the assign tag. In particular, you must have the value mv_shipmode set to assign to shipping, and likewise you must set mv_handling to assign to handling. The salestax and subtotal settings don't require any session variables be set.

96.4.1. Summary

    [assign tag_name=value tag_name=value ...]
    [assign clear=1]
Attributes Description Default
clear Clears all pending 'assign' tag assignments none
handling Assigns an override value for [handling] tags none
salestax Assigns an override value for [salestax] tags none
shipping Assigns an override value for [shipping] tags none
subtotal Assigns an override value for [subtotal] tags none
Other_Characteristics  
Invalidates cache No
Container tag No

ASP-like Perl call:

    $Tag->assign(  { shipping => 2.99, }  );

96.4.1.1. See Also

[handling], [salestax], [shipping], [subtotal], [Shipping]

96.4.2. Description

The assign tag allows you to assign numeric override values to one or more of the following tags:

[handling], [salestax], [shipping], and [subtotal]

An assigned tag will return your value rather than calculating its own until you clear the assignment.

Assignment is persistent within the user's session (unless cleared) and affects only that user.

Assigning an empty string clears the tag's assignment. You can also clear all pending assignments at once with the clear attribute.

For example, the following eliminates salestax and sets shipping to $4.99 regardless of weight and destination:

    [assign salestax=0 shipping=4.99]

This restores the [salestax] tag and eliminates handling charges:

    [assign salestax="" handling=0]

This restores the normal behavior to the [shipping] and [handling] tags:

    [assign clear=1]

Assignment affects only the value returned by a tag. Other behavior, such as formatting for the local currency, is not affected by the assignment.

Note -- you will get an error in the error log (and any pending assignment for the specified tag will be cleared) if you try to assign a value other than a number or the empty string ("").

96.4.2.1. clear

Setting this to a true value clears all pending assignments (i.e., all assignable tags return to normal behavior).

96.4.2.2. shipping

This sets the total value of shipping, rounded to locale-specific fractional digits. Always active if assigned a numeric value. See the [shipping] tag for detail about rounding, etc.

96.4.2.3. handling

This option sets the total value of handling, rounded to fractional digits.


Important note

The [handling] tag is unlike the others in that it will be inactive (despite your assignment) unless the [value mv_handling] variable is true (i.e., a nonzero, non-blank value).


96.4.2.4. salestax

This preempts the salestax calculation. The assigned value is not rounded.

96.4.2.5. subtotal

This preempts the cart subtotal derived from prices. The assigned value is not rounded.

Note that you cannot assign to [total-cost] -- it will always be the sum of the four above.

Before using the assign tag, please be sure you understand the dependencies within the pricing system, such as the relationship between [total-cost] and assigned tags.

96.5. attr-list

This tag is intended for use within embedded perl rather than as a standalone tag within a template (i.e., the [attr-list ...] syntax does not apply).

The $Tag->attr_list($template, $hashref) usage provides a shorthand for accessing values of a hash within embedded perl. It also allows you to control defaults or set up conditional values.

96.5.1. Summary

    $Tag->attr_list($template, $hashref)
Parameters Description Default
hash   DEFAULT_VALUE
Attributes Default
interpolate No
reparse Yes
Other_Characteristics  
Invalidates cache no
Container tag NA (Though the template is technically body text)
Has Subtags No
Nests No

Tag expansion example (ASP-like Perl call):

    [perl tables=products]
        my %opt = ( hashref => 1,
                 sql     => 'select * from  products', );

        my $ary_of_hash = $Db{products}->query(\%opt);

        my $template = <<EOF;
            {sku} - {description} - {price|Call for price}
            {image?}<IMG SRC="{image}">{/image?}
            {image:}No image available{/image:}
            <br>
            More body Text here
            <br>
EOF

        foreach my $ref (@$ary_of_hash) {
            $out .= $Tag->attr_list($template, $ref);
        }
        return $out;
     [/perl]
---
     os28113 - The Claw Hand Rake - Call for price
     <IMG SRC="/mycatalog/images/os28113.gif">

     <br>
     More body Text here
     <br>
     os28006 - Painters Brush Set - 29.99
     No image available

     <br>
     More body Text here
     <br>
     ...

96.5.2. Description

Tags an attribute list with values from a hash. Designed for use in embedded Perl.

Tags according to the following rules:

96.5.2.1. {key}

Inserts the value of the key for the reference. In a database query, this is the column name.

96.5.2.2. {key|fallback string}

Displays the value of {key} or if it is zero or blank, the fallback string (i.e., default).

96.5.2.3. {key true string}

Displays true string if the value of {key} is non-blank, non-zero, or displays nothing if the key is false.

96.5.2.4. {key?} true text {/key?}

Displays true text if the value of {key} is non-blank, non-zero, and nothing otherwise.

96.5.2.5. {key:} false text {/key:}

Displays false text if the value of {key} is blank or zero, and nothing otherwise.

96.5.2.6. hash

This is the hash reference whose keys will be expanded within the template (see above).

96.6. banner

Implements random or rotating banner ads. See also Banner/Ad rotation.

96.6.1. Summary

    [banner category]
    [banner category=my_category other_named_attributes]
Parameters Description Default
category   default
Attributes Default
table banner
r_field (unweighted) rotate
b_field banner
separator (unweighted) ':'
delimiter (unweighted) '{or}'
weighted No
once (weighted) No
c_field (weighted) category
w_field (weighted) weight
interpolate (reparse) No
Other_Characteristics  
Invalidates cache No
Container tag No

Tag expansion example:

    [banner category=my_category]

ASP-like Perl call:

    $Tag->banner(  { category => $key, } );

or similarly with positional parameters,

    $Tag->banner($category, $attribute_hash_reference);

96.6.1.1. See Also

Banner/Ad rotation

96.6.2. Description

Implements random or rotating banner ads. See Banner/Ad rotation in the Interchange Template documentation.

You will need a banner ad table (typically called 'banner') which contains banner data. The following is an example:

code category weight rotate banner
m_3 cat1 7 0 my banner 3
m_1 cat1 1 0 my banner 1
default     1 Default 1{or}Default 2{or}Default 3
m_2 cat1 2 0 my banner 2
t_1 cat2 4 0 their banner 1
t_2 cat2 1 0 their banner 2

96.6.2.1. category

Default: category="default"

This specifies the category for weighted ad, or the table row (i.e., code value) for an unweighted ad.

96.6.2.2. table

Default: table="banner"

Setting 'table="my_banner_table"' forces the tag to refer to 'my_banner_table' rather than the default 'banner' table for banner ad information.

96.6.2.3. r_field

Default: r_field="rotate"

Unweighted ads only.

A table row may include multiple banners in the 'banner' column. The column specified by r_field contains a boolean that determines whether to rotate banners. In the above table example, 'Default 1', 'Default 2' and 'Default 3' would rotate.

96.6.2.4. b_field

Default: b_field="banner"

This specifies the column containing the banner descriptor(s). The default is 'banner'. Note that an entry might be a delimited list of banner descriptors to rotate (see delimiter below).

96.6.2.5. separator

Default: separator=":"

Unweighted ads only.

This sets the separator within the table key (i.e., code) for multi-level categorized ads. See Banner/Ad rotation.

96.6.2.6. delimiter

Default: delimiter="{or}"

Unweighted ads only.

This specifies the delimiter between rotating banner descriptors in the 'banner' column.

96.6.2.7. weighted

The banner tag will not apply weighting from the table unless you set weighted=1. Note that the tag will behave as if you gave it a standard unweighted entry -- it will look for a matching row rather than a matching category.

96.6.2.8. once

Weighted ads only.

If the option once is passed (i.e., [banner once=1 weighted=1], then the banners will not be rebuilt until the total_weight file is removed. See Banner/Ad rotation.

96.6.2.9. c_field

Default: c_field="category"

Weighted ads only.

This specifies the column containing the banner category for weighted ads. The banner tag will display ads from rows in the table whose category matches the category given in the tag, with frequency corresponding to the weights in the table.

96.6.2.10. w_field

Default: w_field="weight"

Weighted ads only.

This specifies the column containing the banner weight.

96.7. bounce

96.7.1. Summary

Parameters: href if

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

None. This tag doesn't work with embedded Perl due to special processing.

    [bounce href if]
Parameters Description Default
href   DEFAULT_VALUE
if   DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache no
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [bounce href if]
---
    TAG RESULT

ASP-like Perl call:

None. This tag doesn't work with embedded Perl due to special processing.

96.7.2. Description

The [bounce ...] tag is designed to send an HTTP redirect (302 status code) to the browser and redirect it to another (possibly Interchange-parsed) page.

It will stop ITL code execution at that point; further tags will not be run through the parser. Bear in mind that if you are inside a looping list, that list will run to completion and the [bounce] tag will not be seen until the loop is complete.

Example of bouncing to an Interchange parsed page:

        [if !scratch real_user]
        [bounce href="[area violation]"]
        [/if]

Note the URL is produced by the [area ...] ITL tag.

Since the HTTP says the URL needs to be absolute, this one might cause a browser warning:

        [if value go_home]
        [bounce href="/"]
        [/if]

But running something like one of the Interchange demos you can do:

        [if value go_home]
        [bounce href="__SERVER_NAME__/"]
        [/if]

        [if value go_home]
        [bounce href="/"]
        [/if]

96.7.2.1. href

96.7.2.2. if

96.8. calc

Calculates the value of the enclosed arithmetic expression.

96.8.1. Summary

    [calc] Expression [/calc]

No parameters

No attributes (though you can break it if you set 'interpolate=0')

Other_Characteristics  
Invalidates cache No
Has Subtags No
Container tag Yes
Nests No

ASP-like Perl call:

There is never a reason to call this tag from within Perl or ASP code. Simply do the calculation directly.

96.8.2. Description

Calculates the value of the enclosed arithmetic expression.

Use it as follows: [calc] Expression [/calc]

The enclosed region where the arguments are calculated according to normal arithmetic symbols. For instance:

    [calc] 2 + 2 [/calc]

will expand to:

    4

The [calc] tag is really the same as the [perl] tag, except that it doesn't accept arguments, interpolates surrounded Interchange tags by default, and is slightly more efficient to parse.

Tip: The [calc] tag will remember variable values inside one page, so you can do the equivalent of a memory store and memory recall for a loop.

ASP Note: There is never a reason to call this tag from within Perl or ASP code.

96.9. calcn

Calculates the value of the enclosed arithmetic expression.

96.9.1. Summary

    [calcn] Expression [/calcn]

No parameters

No attributes

Other_Characteristics  
Invalidates cache No
Has Subtags No
Container tag Yes
Nests No

ASP-like Perl call:

There is never a reason to call this tag from within Perl or ASP code. Simply do the calculation directly.

96.9.2. Description

Equivalent to the [calc] tag, except that it does not interpolate by default.

NOTE: This tag was introduced in Interchange 4.9 and is therefore not available in earlier versions.

96.10. cart

96.10.1. Summary

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->cart(
        {
         name => VALUE,
        }
    )

 OR

    $Tag->cart($name);
    [cart name]
Parameters Description Default
name   DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache YES
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [cart name]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->cart(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->cart(name, $attribute_hash_reference, $body);

96.10.2. Description

Sets the name of the current shopping cart for display of shipping, price, total, subtotal, shipping, and nitems tags.

96.10.2.1. name

96.11. catch

The page content contained within the [catch label][/catch] block executes if the correspondingly labelled try block fails.

You can also return a result based on the error message caught in the try block with paired subtags, like this:

    [error message]body text[/error message]

Note that this feature excises all tag/endtag pairs if interpolation is turned off, so the catch tag interpolates by default.

See also [try].

96.11.1. Summary

    [try my_label]
        Body text to return if no error
    [/try]
    .
    .
    .
    [catch label=my_label other_named_attributes]
        [/Pattern matching error message 1/]
            Return this if error 1 occurs
        [/Pattern matching error message 1/]

        [/Pattern matching error message 2/]
            Return this if error 2 occurs, etc.
        [/Pattern matching error message 2/]

        Default body text to process if try block caused an error
    [/catch]
Parameters Description Default
label The label shared by the paired try and catch blocks 'default'
Attributes Default
interpolate Yes
reparse Yes
Other_Characteristics  
Invalidates cache No
Container tag Yes
Has Subtags
    [Error message text]
      body

    [/Error message text]

Tag expansion example

Ignoring whitespace, the following would return division result if successful, 0 on a division by zero, or an error message:

    [set divisor]0[/set]
    [try label=div]
        [perl] eval(1 / [scratch divisor]) [/perl]
    [/try]
    [catch div]
        [/Illegal division by zero/]
            0
        [/Illegal division by zero/]
        [/eval "string" trapped by operation mask/]
            Perl Safe error
        [/eval "string" trapped by operation mask/]
        Other division error
    [/catch]
---
   Perl Safe error

ASP-like Perl call:

    $Tag->catch(  { label => I<'my_label'>, },
                  $body  );

or similarly with positional parameters,

    $Tag->catch($label, $attribute_hash_reference, $body);

96.11.1.1. See Also

try

    [catch]
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache No
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [catch]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->catch(  {
}, $body  );

or similarly with positional parameters,

    $Tag->catch(, $attribute_hash_reference, $body);

96.11.2. Description

The page content contained within the [catch label][/catch] block executes if the correspondingly labelled try block fails. The catch block executes in place on the page if triggered (i.e., it does not return its result in place of the try block).

You can also return a result based on the error message caught in the try block with paired subtags, like this:

    [/error message/]special catch block for the error[/error message/]

The error message to use in the special block will generally be part of the entry the error generates in your error log. For example, a division by zero error generates something like the following in the error log:

   127.0.0.1 4cU3Pgsh:127.0.0.1 - [24/May/2001:14:45:07 -0400]\
   tag /cgi-bin/tag72/tag Safe: Illegal division by zero\
   at (eval 526) line 2.

(note that trailing backslashes in the example indicate a continued line).

96.11.2.1. label

This is the label specifying the corresponding [try block. Defaults to 'default'.

96.12. cgi

Returns the the current value of the named CGI input variable. HTML-escapes Interchange tags in the result for security.

Can also set a new CGI value within the current page.

96.12.1. Summary

    [cgi name]
    [cgi name=cgi_var_name other_named_attributes]
Parameters Description Default
name This is the name of the CGI variable whose value you want. None
Attributes Default
set none
hide No
filter none
keep (with filter) No
enable_html No
interpolate (reparse) No
Other_Characteristics  
Invalidates cache Yes

Tag expansion example:

Assuming CGI variable 'foo' = 'bar',

    [cgi foo]
---
    bar

ASP-like Perl call:

    $Tag->cgi( { name => var_name } );

    # or if you simply want the value:
    $CGI->{var_name};

    # or:
    $CGI::values{var_name};

or similarly with positional parameters,

    $Tag->cgi($name, $attribute_hash_reference);

96.12.2. Description

Displays the value of a CGI variable submitted to the current page. This is similar to [value ...], except it displays the transitory values that have been submitted with the current request.

For instance, if you access the following URL:

        http://VENDURL/pagename?foo=bar

bar will be substituted for [cgi foo].

This is the same as $CGI->{foo} in embedded Perl.

96.12.2.1. name

This is the name of the CGI variable whose value you want.

96.12.2.2. set

You can change a value with 'set=new_value'. The tag will return the CGI value you set unless you also set the hide=1 attribute.

Note that this is only available in new-style tags, for safety reasons.

96.12.2.3. hide

Setting hide=1 suppresses the tag's return value, which can be useful with the set attribute.

96.12.2.4. filter

See the filter tag for a list of filters.

Setting 'filter="filter"' modifies the named CGI variable with the specified filter.

96.12.2.5. keep (with filter)

Set keep=1 if you want the tag to return a filtered result but do not want the filter to modify the CGI value itself in the $CGI::values hash.

96.12.2.6. default

This sets a return value in case the named CGI variable is missing or otherwise false. The following will expand to "Using default":

    [cgi name=myname set=0 hide=1]
    [cgi name=myname default="Using default"]

96.12.2.7. enable_html

Any '<' characters will normally be converted into '&lt;' for safety reasons. This conversion can be disabled using 'enable_html=1'.

96.13. checked

96.13.1. Summary

Parameters: name value

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the parameters as the last argument. This may mean that there are parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->checked(
        {
         name => VALUE,
         value => VALUE,
        }
    )

 OR

    $Tag->checked($name, $value, $ATTRHASH);
    [checked name value other_named_attributes]
Parameters Description Default
case   DEFAULT_VALUE
cgi   DEFAULT_VALUE
default   DEFAULT_VALUE
name   DEFAULT_VALUE
multiple   DEFAULT_VALUE
value   DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache YES
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [value name=example set=neato]
    <INPUT TYPE=checkbox NAME=neato VALUE=1 [checked name=neato value=1]>
    <INPUT TYPE=checkbox NAME=silly VALUE=1 [checked name=silly value=1]>
    <INPUT TYPE=checkbox NAME=neato VALUE=1 CHECKED>
    <INPUT TYPE=checkbox NAME=silly VALUE=1 >

96.13.2. Description

You can provide a "memory" for drop-down menus, radio buttons, and checkboxes with the [checked] and [selected] tags.

    <INPUT TYPE=radio NAME=foo
            VALUE=on [checked name=foo value=on default=1]>
    <INPUT TYPE=radio NAME=foo
            VALUE=off [checked name=foo value=off]>

This will output CHECKED if the variable var_name is equal to value. Not case sensitive unless the optional case=1 parameter is used.

The default parameter, if true (non-zero and non-blank), will cause the box to be checked if the variable has never been defined.

Note that CHECKBOX items will never submit their value if not checked, so the box will not be reset. You must do something like:

    <INPUT TYPE=checkbox NAME=foo
            VALUE=1 [checked name=foo value=1 default=1]>
    [value name=foo set=""]

By default, the Values space (i.e. [value foo]) is checked -- if you want to use the volatile CGI space (i.e. [cgi foo]) use the option cgi=1.

Use the parameter default=1 to specify that this checkbox should be marked CHECKED if the value/CGI variable has never been set.

If the parameter multiple=1 is set, the value parameter can contain multiple (stacked) values that should be checked, separated by ASCII null characters ("\0" in Perl).

96.13.2.1. case

96.13.2.2. cgi

96.13.2.3. default

96.13.2.4. name

96.13.2.5. multiple

96.13.2.6. value

96.14. control

Returns named scratchpad field or copies named scratch variable to scratchpad. Returns value specified by 'default' attribute if scratchpad variable is undefined or empty. Calling without a name moves to next scratchpad. Calling without a name and 'reset=1' returns to first scratchpad page.

96.14.1. Summary

    [control name default other_named_attributes]
Parameters Description Default
default Value to return if scratchpad variable missing or empty DEFAULT_VALUE
name Name of scratchpad variable to set or return DEFAULT_VALUE
reset Resets scratchpad (i.e. $::Control array) by setting special scratch variable 'control_index' to 0. Control_index is an index into the $::Control == $Vend::Session->{control} array of hashrefs.
  • (must not specify name; may specify default)
DEFAULT_VALUE
set Copies named scratch variable (i.e., from $::Scratch) to scratchpad with current control index. DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache no
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [control name default]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->control(  { default => VALUE_default
                      name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->control(name,default, $attribute_hash_reference, $body);

96.14.2. Description

Returns named scratchpad field or copies named scratch variable to scratchpad. Returns value specified by 'default' attribute if scratchpad variable is undefined or empty. Calling without a name moves to next scratchpad. Calling without a name and 'reset=1' returns to first scratchpad page.

96.14.2.1. default

Value to return if scratchpad variable missing or empty

96.14.2.2. name

Name of scratchpad variable to set or return

96.14.2.3. reset

Resets scratchpad (i.e. $::Control array) by setting special scratch variable 'control_index' to 0. Control_index is an index into the $::Control == $Vend::Session->{control} array of hashrefs.

96.14.2.4. set

Copies named scratch variable (i.e., from $::Scratch) to scratchpad with current control index.

96.15. control_set

Bulk-sets scratchpad variables on the scratchpad page specified by 'index'. Note that, unlike [control], this does not copy values from scratch.

96.15.1. Summary

This example sets var_one, var_two and var_three in the scratchpad on page 5 (index begins with 0).

    [control_set index=4]
        [var_one]var_one_value[/var_one]
        [var_two]var_two_value[/var_two]
        [var_three]var_three_value[/var_three]
    [/control_set]

Parameters: index

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before the container text argument. This may mean that there are parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [control_set] FOO [/control_set]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->control_set(
        {
         index => VALUE,
        },
        BODY
    )

 OR

    $Tag->control_set($index, $ATTRHASH, $BODY);
    [control_set index other_named_attributes]
Parameters Description Default
index   DEFAULT_VALUE
Attributes Default
interpolate No
reparse Yes
Other_Characteristics  
Invalidates cache no
Container tag Yes
Has Subtags No
Nests No

Tag expansion example:

    [control_set index]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->control_set(  { index => VALUE_index
}, $body  );

or similarly with positional parameters,

    $Tag->control_set(index, $attribute_hash_reference, $body);

96.15.2. Description

Bulk-sets scratchpad variables on the scratchpad page specified by 'index'. Note that, unlike [control], this does not copy values from scratch.

96.15.2.1. index

96.16. counter

96.16.1. Summary

Parameters: file start date sql

Positional parameters: file

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->counter(
        {
         file => VALUE,
         sql => VALUE,
         start => VALUE,
         date => 'local' || 'gmt',
        }
    )

 OR

    $Tag->counter($file, $ATTRHASH);

Attribute aliases

            name ==> file
    [counter file]
Parameters Description Default
file   DEFAULT_VALUE
name Alias for file DEFAULT_VALUE
sql Asserts a SQL-based counter DEFAULT_VALUE
date Asserts a date-based counter DEFAULT_VALUE
Attributes Default
interpolate (reparse) No
Other_Characteristics  
Invalidates cache YES
Container tag No
Has Subtags No
Nests Yes

Tag expansion example:

    [counter file]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->counter(  { file => VALUE_file, sql => 'table:seq', start => VALUE, }  );

or similarly with positional parameters,

    $Tag->counter(file, $attribute_hash_reference);

96.16.2. Description

Manipulates a persistent counter, by default incrementing it and returning the new value.

The counter value is stored in the specified file. If the file name begins with a "/" then it is an absolute path. Otherwise, it is relative to VendRoot. The default file is etc/counter. If the file does not exist, it is created and initialized to the value of the start parameter.

If the optional sql attribute is used, a SQL sequence will be used. Currently MySQL and Postgres are supported. The sequence must already exist. If no bypass parameter is sent, the table in the sequence callout (explained below) will be used and must be an Interchange table (i.e. set up with Database setting). If bypass is set, then the DSN for the sequence will be passed in the dsn parameter.

If the optional date attribute is used, a date-based counter will be made. It takes the form of the date in YYYYMMDD followed by the start value, by default 0001. When the date changes, the counter will flip over to the next day and the beginning start value.

WARNING: This tag may not work under Safe, i.e. in embedded Perl.

Additional parameters:

96.16.2.1. decrement=1

Causes the counter to count down instead of up. This option is not applicable to SQL counters.

96.16.2.2. start=50

Causes a new counter to be created and to start from 50 (for example) if it did not exist before. This option is not applicable to SQL counters.

96.16.2.3. value=1

Shows the value of the counter without incrementing or decrementing it. This option is not applicable to SQL counters.

96.16.2.4. sql="table:sequence"

The table and sequence name of the SQL counter.

If the type of database is Postgres, the table is used to derive the database and the sequence will be a named sequence independent of the table; the sequence is incremented and accessed by "SELECT nextval('sequence_name')".

If the type of database is MySQL, an AUTO_INCREMENT key column is assumed and an insert of 0 followed by "select last_insert_id()" will increment then access the counter.

96.16.2.5. date="local"

Specifies the counter will be date-based with local time.

96.16.2.6. date="gmt"

Specifies the counter will be date-based with GMT.

96.16.2.7. file

96.16.3. SQL Counter Examples

To set up a Postgres counter, simply create a named sequence in the database:

  CREATE SEQUENCE "foo" start 1 increment 1 maxvalue 2147483647 minvalue 1 cache 1

You will want to make sure you have an Interchange table that uses that database ("sometable" in the below example).

Then access it with:

    [counter sql="sometable:foo"]

You can create as many sequences as you like.

To set up a MySQL counter, add a table to your MySQL database in catalog.cfg or other place like dbconf/mysql:

  Database sequence_name sequence_name.txt dbi:mysql:test_foundation
  Database sequence_name COLUMN_DEF "id=int NOT NULL AUTO_INCREMENT PRIMARY KEY"

Make sure you set up the sequence.txt file if you want Interchange to create the table for you. Otherwise you can create the table yourself from a mysql client:

mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it with:

    [counter sql="sequence_name:sequence_name"]

Alternatively, you can create the table without Interchange definition as long as it is in the same database as an Interchange table:

  mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it by calling the Interchange-defined table name followed by the table that has the AUTO_INCREMENT key:

    [counter sql="products:sequence_name"]

To set up an Oracle counter, create a sequence:

  SQL> CREATE SEQUENCE foo START WITH 10000 INCREMENT BY 1
                 MAXVALUE 2147483647 MINVALUE 1 CACHE 2;

Then access via a table already connected to Oracle, in below sometable:

    [counter sql="sometable:foo"]
  Database sequence_name sequence_name.txt dbi:mysql:test_foundation
  Database sequence_name COLUMN_DEF "id=int NOT NULL AUTO_INCREMENT PRIMARY KEY"

Make sure you set up the sequence.txt file if you want Interchange to create the table for you. Otherwise you can create the table yourself from a mysql client:

mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it with:

    [counter sql="sequence_name:sequence_name"]

Alternatively, you can create the table without Interchange definition as long as it is in the same database as an Interchange table:

  mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it by calling the Interchange-defined table name followed by the table that has the AUTO_INCREMENT key:

    [counter sql="products:sequence_name"]

96.17. currency

96.17.1. Summary

Parameters: convert noformat

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Interpolates container text by default.

This is a container tag, i.e. [currency] FOO [/currency]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->currency(
        {
         convert => VALUE,
         noformat => VALUE,
        },
        BODY
    )

 OR

    $Tag->currency($convert, $noformat, $BODY);
    [currency convert noformat]
Parameters Description Default
convert   DEFAULT_VALUE
noformat   DEFAULT_VALUE
Attributes Default
interpolate No
reparse Yes
Other_Characteristics  
Invalidates cache no
Container tag Yes
Has Subtags No
Nests No

Tag expansion example:

    [currency convert noformat]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->currency(  { convert => VALUE_convert
                       noformat => VALUE_noformat
}, $body  );

or similarly with positional parameters,

    $Tag->currency(convert,noformat, $attribute_hash_reference, $body);

96.17.2. Description

When passed a value of a single number, formats it according to the currency specification. For instance:

    [currency]4[/currency]

will display:

    4.00

or something else depending on the Locale and PriceCommas settings. It can contain a [calc] region. If the optional "convert" parameter is set, it will convert the value according to PriceDivide> for the current locale. If Locale is set to fr_FR, and PriceDivide for fr_FR is 0.167, the following sequence

    [currency convert=1] [calc] 500.00 + 1000.00 [/calc] [/currency]

will cause the number 8.982,04 to be displayed.

96.17.2.1. convert

96.17.2.2. noformat

96.18. data

96.18.1. Summary

Main Parameters: table field key

Positional parameters in same order.

Additional parameters: hash foreign value

The attribute hash reference is passed to the subroutine after the parameters as the last argument. This may mean that there are parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->data(
        {
         table => VALUE,
         field => VALUE,
         key => VALUE,
        }
    )

 OR

    $Tag->data($table, $field, $key, $ATTRHASH);

Attribute aliases

            base ==> table
            code ==> key
            col ==> field
            column ==> field
            database ==> table
            name ==> field
            row ==> key
    [data table field key other_named_attributes]
Parameters Description Default
base Alias for table DEFAULT_VALUE
code Alias for key DEFAULT_VALUE
col Alias for field DEFAULT_VALUE
column Alias for field DEFAULT_VALUE
database Alias for table DEFAULT_VALUE
field   DEFAULT_VALUE
hash   DEFAULT_VALUE
key   DEFAULT_VALUE
name Alias for field DEFAULT_VALUE
row