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
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 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
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.
You can avoid quotes around r; it is predefined as a constant by ERW, so the lack of quotes will not generate any warning.
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
must be a printf()-like format string (it must be
interpreted by PHP), whereas
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
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.
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.
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", ")" );
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:
As an example,
$D["book"]["display"]["fmtString"] = "%s: %s %[, ]s"; $D["book"]["display"]["field"] = array( "title", "author", "loan_person->lname" );
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
to any string.
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:
Only for filesets; contains the MIME type of the file (it is derived from the filename extension).
Only for filesets; contains the original filename if you are using original filenames.
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.
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.
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
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" );
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", ")" );
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)" );
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" );
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
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";
$D["loan"]["orderBy"] = "loan.startdate desc";
$D["subscriber"]["orderBy"] = "person.lname";
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).
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
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;
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;
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).
The second array controlling filters is
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
for relationships types, and
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;
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.
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"] = ">";