Custom Files

The first customisation layer is defined by means of customisation files. By default, they are contained in a directory named custom located where the run-time environment PHP scripts are. You can create a customisation file for each entity type, relationship type and instance of fileset type you would like to customise. The file must be named as the identifier of the type postfixed with .php. A instance of fileset raising from an attribute A of an entity type T has identifier T_A, and then the same rule applies.

There is also a default customisation file that is used to change defaults throughout all types. It is named as the identifier of the root element of your ERL file postfixed with .php (in our library example, it would be named library.php). Each section on customisation specifies how to change the defaults using this file, whenever possible.

Your custom files are executed in the same environment of a hook: thus, you can tweak customisation using information such as the name of the user. Customisation files, however, should be light, as they are loaded each time a type is used.

All customisation in custom files is performed by setting certain keys of the array $D: the first key is always the name of the type that is being customised (e.g., $D["person"]). The custom files are loaded from higher to lower types, and this allows you to customise higher types from the custom file of a lower type. This is most useful: for instance, you could decide to customise an attribute of person in a different way when it appears in the form of a subscriber. To do so, you just need to put in the custom file for subscriber a suitable entry starting with $D["person"].

Caution

Your custom files are executed as PHP scripts, but they must emit no output. In particular, always check that there are no blank lines after the processing-instruction delimiter ?>.

The Type Array

The definition file of an entity type, relation type or fileset with attributes contains an associative array that specifies the type of each editable element, whether it is an attribute or a relation. A relationship type R from entity type A to entity type B is named R_B in the definition file for A, and R_A in the definition file for B.

The type array is named $D[type]["type"] (all information from definition files is stored in a associative tree contained in the $D variable). By assigning a certain ERW type to a variable, you can change the way it is edited. For instance,


$D["loan"]["type"]["duration"] = r;

will tell ERW that, in our library example, the duration should be chosen via a checkbox rather than via a drop-down list.

Note

You can avoid quotes around r; it is predefined as a constant by ERW, so the lack of quotes will not generate any warning.

Customising Labels

Each time ERW has to display an entity, it uses a label for that entity. The label automatically set up is simply the content of the first attribute specified for the entity type, but it can be customised. The same holds for labels of relationships with attributes.

The array controlling the label of an element is $D[type]["display"]. More precisely, $D[type]["display"]["fmtString"] must be a printf()-like format string (it must be interpreted by PHP), whereas $D[type]["display"]["field"] must be an array of attribute specifiers and constant strings, whose values will be used together with the format string. Of course, the number of elements of $D[type]["display"]["field"] must match the number of format specifiers in the format string.

Certain data, such as enumerative type or thousand-separated digits, are automatically formatted in the same way they would be presented to users in forms. In this cases, you should always use a %s directive in the format string. The %d directive can be used only with nonformatted numeric types.

Note

ERW is usually able to distinguish whether a string is a constant or an SQL specifier. In case it gets confused, just start your constant string with ': the quote will not be printed, but ERW will know that you meant literally what follows.

Format String Extensions

The format string supports two useful extensions, which have been thought to handle the case of NULLvalues and multiple-value attribute specifiers.

If a directive has a ? just after %, then the directive is optional. If the associated parameter is empty or NULL then the directive, the preceding one and the following one are marked as dead, and will not be actually printed (note that an optional directive cannot be marked as dead). This allows you to build complex specifications that add markup (such as brackets, hyphens and so on) depending on the presence of a certain parameter.

As an example,


$D["book"]["display"]["fmtString"] = "%s: %s %s%?s%s";
$D["book"]["display"]["field"] = 
     array( "title", "author", " (", "isbn", ")" );
would display a book by showing the author followed by a colon, the title and then the ISBN code between parentheses, but only if the code has been specified.

Warning

There are situation (such as editing weak entities with ERW type r1e) in which ERW has no way to know the attributes of other entities. In this case, they are all set to NULL. Your format strings must always be written so that they handles these cases gracefully.

The other useful extension allows to format lists (of formatted values) using a given separator and additional formatting. More precisely, ERW accepts directives of this form:


%alignment-width-precision-length[separator]standard-format-specifier

When printing a directive of this form, ERW expects as corresponding field a multiple-value attribute. Each element of the list of values will be formatted using the standard-format-specifier. Then, the resulting strings will be concatenated using the given separator (which can also be delimited by (, < or {), and finally the resulting string will be printed using the given alignment, width, ecc.: essentially, the string will be formatted with a directive obtained by stripping the separator and whatever follows, and appending s.

As an example,


$D["book"]["display"]["fmtString"] = "%s: %s %[, ]s";
$D["book"]["display"]["field"] = 
     array( "title", "author", "loan_person->lname" );
would display a book by appending to the title and author the list, separated by commas, of the people that borrowed the book (note however that in this case you could get doubles if the same person borrowed many times the same book).

Tabular Displays

Sometimes, you could prefer a rigidly aligned, tabular display in which each field occupies a fixed amount of space. This is easy to obtain using printf()'s sophisticated field width and alignment control. However, you will also need a fixed-width font, and a table header specifying the name of the columns. To obtain this effect, you can set the variable $D[type]["display"]["head"] to any string.

Virtual Attributes

When building labels, sometimes you can use virtual attributes, which do not really exist in the database, but are generated at run-time. These are the currently implemented virtual types:

MIMEtype

Only for filesets; contains the MIME type of the file (it is derived from the filename extension).

original

Only for filesets; contains the original filename if you are using original filenames.

fileSizeB, fileSizeKB, fileSizeMB, fileSizeKiB, fileSizeMiB

Only for filesets; contains the size of the file in the given unit (note that K means 1000, Ki means 1024 and so on). It is a float, so you can format it using the standard printf() conventions.

Displaying Owners and Groups

ERW sets up two virtual relationship types, owner_usr and share_grp, that can be used as any other relationship type in an attribute specifier to display information related to an entity belonging to a type that has element-based authorisation.

Displaying Relationships

Display customisation allows you to specify a label using the attribute values of a relationship. The resulting label will be juxtaposed on the right to the label of the related entity when displaying a relationship in an entity form. For instance, in Figure 2 in the Section called A Simple Example in Preface loans are displayed showing the label of the borrowed book (the related entity) followed by a label derived from the relationship attribute values (type of loan and dates). Thus, your labels for relationships must be written with this arrangement in mind (for instance, they would better start with a space).

However, ERW allows you also to edit directly relationships. In this case, you may want to specify a more complex label, possibly depending also on the attribute values of the entities related by the relationship.

To this purpose, ERW provides the $D[type]["fullDisplay"] customisation variable. A good example for loan is the following one, which would give the output shown in Figure 6 in the Section called A Simple Example in Preface:


$D["loan"]["fullDisplay"]["fmtString"] = 
  "%-10.10s %-10.10s %-36.36s %10.10s %10.10s";
$D["loan"]["fullDisplay"]["head"] = 
  "First name Last name  Book title                           Start date  End date";
$D["loan"]["fullDisplay"]["field"] = 
      array( "person_0.fname", "person_0.lname",
             "book_1.title",
             "startdate", "enddate"  
      );

Accessing subtypes

The qualifier part of an attribute specifier may be also used to access attributes of a subtype. Of course, the attribute could not exist at all, because the entity specified is not of that type: in this case, the value will be NULL.

Interestingly, we can use this fact to build labels that are conditional on the type of an entity. For instance, if we have an entity document with attribute title and subtypes publication (with mandatory attribute journal) and techrep (with mandatory attribute number), we can specify a label like:


$D["document"]["display"]["fmtString"] = "%s %s%?s%s%s%?d%s";
$D["document"]["display"]["field"] = 
        array("title", "(", "publication.journal", ")", 
                       "(", "techrep.number", ")" );
As a result, each document has an optional item between parentheses if it is a publication or a technical report: the journal or the number, respectively.

We can push further this technique exploiting the ubiquitous id attribute. Since subtyping is realised by set inclusion, an entity with a certain id is really of a more specific type only if the same id exists in a subtype. This can be exploited as follows:


$D["document"]["display"]["fmtString"] = "%s %s%?.0s%s%s%?.0s%s";
$D["document"]["display"]["field"] = 
        array("title", "(", "publication.id", "Publication)", 
                      "(", "techrep.id", "Technical Report)" );
The id field is used to trigger the %?.0s specifier, but because of the limitation on the output (.0), the id is not really printed. Rather, the strings (Publication) and (Technical Report) are only printed if the document is a publication or a techrep, respectively.

Local Customisation

It can happen that the standard way to label an entity does not work in all situations. The typical example is given by weak entities: suppose again you have editions for books, and that editions are weak entities whose owner is the respective book. Certainly, to label in general an edition you will use also fields from the owner, for example title and author, by means of attribute specifiers.

However, you will more likely access editions in the context of a specific book, using a suitable ERW type. In this case, however, you need just to show information about the edition, and not information about the owner, which is already currently displayed.

For this kind of situation, ERW offers local customisation. For each relationship type, you can specify a label for the related entities, which will override the standard one. The label is specified using the usual keys fmtString and field, but preceded by the key chain $D[type]["display"]["relationship-type_other-entity-type"]. For instance,


$D["book"]["display"]["regards_edition"]["fmtString"] = "%s, %d";
$D["book"]["display"]["regards_edition"]["field"] = 
  array( "publisher", "year" );
will list editions (in the form of a book) just by their publisher and year (we are assuming that the identification function going from edition to book is named regards, and that edition has attributes named publisher and year).

Ordering Elements

By default, entities and relationships are ordered with respect to their identifier; this, however, is not very meaningful. You can specify the display order of entities and relationships by setting the variable $D[type]["orderBy"] to a string containing an SQL order by-like order specification: a list of comma-separated attribute specifiers, possibly followed by asc or desc (for ascending or descending order). For instance,


$D["book"]["orderBy"] = "book.author,book.title";
would order books by author and title, in ascending order. Instead,

$D["loan"]["orderBy"] = "loan.startdate desc";
would put in front the most recent loans, and

$D["subscriber"]["orderBy"] = "person.lname";
would order subscribers by last name.

Note that you cannot order absorbed relationship types, and that you cannot use non-monodrome relationship types in an order specification (in any case, it would not be meaningful).

Customising Filters

Each time ERW has to display a list of entities, relationships or files, it can provide a filter to allow the user to restrict the available choices. The default filter works on the content of the first attribute, but it can be customised. If several filters are specified, they work in boolean conjunction. Moreover, multi-value attribute specifier generate a filter that is satisfied if any of the values in the associated list satisfy the value in the filter.

To customise filtering, you specify a list of attributes over which filtering must be performed. Each attribute has a level, that is, a real number between 0 and 1 (inclusive, with default 1/2) that expresses how significant that attribute is with respect to filtering.

Each list displayed by ERW has a default level, too: it is 0 for main lists, 1/2 for selection lists and 1 elsewhere. For each list, ERW will display only those filter whose level is greater than or equal to the list level, in definition order. Thus, by default main lists and selection lists get all filters, whereas no filters are used elsewhere. Note that relationship types without filters inherit the filters of their source/target entity types.

The first array controlling filters is $D[type]["filter"]. More precisely, for each attribute specifier (the first key), you can specify an ERW type (second key "type"), an optional label (second key "label"; if the label is omitted, the label of the attribute will be used instead) and an optional filter level (second key "level"; default 1/2). Presently the ERW type must be the default ERW type associated to the ERL type of the attribute, except for the ERL type a, for which the type t must be used. Since there is a default filter, and many levels of keys, it is usually a good idea to first reset the array and then fill one-by-one the desired entries.

As an example,


$D["book"]["filter"] = array();
$D["book"]["filter"]["author"]["type"] = t;
$D["book"]["filter"]["author"]["label"] = "Author(s)";
$D["book"]["filter"]["title"]["type"] = t;
$D["book"]["filter"]["isbn"]["type"] = t;
$D["book"]["filter"]["isbn"]["level"] = 0.1;
will allow to select a book by author, title and ISBN code in the main list, but just by author and title elsewhere. Moreover, the author filter will be labelled "Author(s)".

You have the full power of attribute specifiers at your disposal. For instance, you can filter subscribers on their first and last name:


$D["subscriber"]["filter"] = array();
$D["subscriber"]["filter"]["person.fname"]["type"] = t;
$D["subscriber"]["filter"]["person.lname"]["type"] = t;

Multi-value attributes may be very useful, too, assuming you want filter out books that have been lent to someone in particular:


$D["book"]["filter"] = array();
$D["book"]["filter"]["loan_person->lname"]["type"] = t;

And, of course, you can access the source/target entity types of a relationship type, and their supertypes. For instance,


$D["loan"]["filter"] = array();
$D["loan"]["filter"]["person_0.fname"]["type"] = t;
$D["loan"]["filter"]["person_0.lname"]["type"] = t;
$D["loan"]["filter"]["book_1.author"]["type"] = t;
$D["loan"]["filter"]["book_1.author"]["label"] = "Author(s)";
$D["loan"]["filter"]["book_1.title"]["type"] = t;
$D["loan"]["filter"]["startdate"]["type"] = d;
$D["loan"]["filter"]["enddate"]["type"] = d;
would have the following effect: when editing loans, you would get a filter allowing to select loans by borrower's first/last name, book author/title, and loan start/end date. On the other hand, the filters for selecting the loans of a certain person (in its form) would be the book title and the loan start/end date (analogously for a book).

Filtering on Owners and Groups

Must as in the case of labels, ERW sets up two virtual relationship types, owner_usr and share_grp. They behave as having type r1, and you can use them not only in specifiers, but also directly as attributes, using the type r1s. As a result, the filter will contain a drop-down list with available users (or groups).

Filtering Levels

The second array controlling filters is $D[type]["filterLevel"]. Its first key is a list type (as explained in the Section called The Button Hook), and its second key (which is to be specified only if the first key is not main) is of the form relationship-type_other-entity-type for relationships types, and attribute-name for filesets. It specifies a filter level (i.e., a real number between 0 an 1 inclusive) that overrides the default for any of the lists appearing in a form, allowing fine-grained customisation.

As an example,


$D["book"]["filterLevel"]["rel"]["loan_person"] = 0;
will set up all filters for searching persons who borrowed a book.

The default filter level can be changed in the default customisation file, using the key chain $D["*"]["filterLevel"] followed by a key giving the type of list (as explained in the Section called The Button Hook). Thus, for instance, $D["*"]["filterLevel"]["rel"] = 0 would set all filters for all relationship lists.

Default Values

Sometimes, in particular with very large databases, you may want to present since the start a list which selects a subrange of items. to this purpose, ERW allows you to set default values for filters. Similarly to default value for attributes, you have to specify an SQL expression that will be evaluated to produce the initial filter value. The expression must be stored using the key default (which is as the same level as type, label etc.). For filters with operators, you can also specify the preferred operator using the key operator. For instance,


$D["loan"]["filter"] = array();
$D["loan"]["filter"]["startdate"]["type"] = d;
$D["loan"]["filter"]["startdate"]["default"] = "'2001-01-01";
$D["loan"]["filter"]["startdate"]["operator"] = ">";
would show at start loans that began in the current millennium.