Programming in Sitellite
Chapter 6: Custom Content Types (Collections)
What is a collection?
Collections in Sitellite
When a database table or file structure becomes a collection, it adopts a number of benefits over the traditional ways of managing items in a database or filesystem. These include:
- Versioning – Keeps track of every change made to each item, and allows you to view and even revert to previous versions of an item -- even after it's been deleted.
- Audit trail – Keeps track of who made what change and when it was made.
- Standardized editing – Collections become available through both the Sitellite Web View as well as the collection list in the Sitellite Control Panel, reducing the amount of learning involved in training existing editors for new content types.
- Standard API – Sitellite provides a built-in set of classes for accessing any collection programmatically, creating a standard way of programming for any type of collection.
- Automatic multilingual capabilities through Sitellite 5's multilingual/translation system.
Creating a collection
A collection starts with two things: A data source (usually a database table) and a collection definition file. The collection definitions are stored as a series of INI files in the "inc/app/cms/conf/collections" directory.
Let's build a simple collection definition for the myapp_listing database table we created earlier. To start, create a blank file named "inc/app/cms/conf/collections/myapp_listing.php".
General settings
Source means the data source being managed as a collection. In our example, this is the original myapp_listing database table.
Store means the location used to store the version changes to items in the collection. In our example, this will be a secondary database table that we will create shortly.
The reason for abstracting the two into separate components is so that, if needed, you can change the underlying data source or version storage layers (ie. changing the store from a database table to using the Concurrent Versioning System (CVS) application to manage versioning).
The following will be the general section of our collection definition file:
; <?php /* [Collection] name = myapp_listing display = Listings singular = Listing key_field = id title_field = name title_field_name = Name summary_field = description body_field = description [Source] name = Database [Store] name = Database
Browse options
Browse options are used to determine which fields should be shown as table columns in the Sitellite Control Panel's collection browsing screen. For this, we'll show all three fields by adding the following to our collection definition file. This sets the column width for each field and the maximum text length to show for each text field. Text longer than the length will automatically be cropped with a '...' placed at the end.
[browse:id] header = ID width = "10%" [browse:name] header = Name width = "25%" length = 30 [browse:description] header = Description width = "55%" length = 80
Sitellite's browse screen has a powerful feature called the "Search Parameters" box. This allows users to perform compound queries on collections in just a few clicks. For example, an editor might want to search for all of the news stories under the "Sports" category that have a status of "Pending".
These types of queries can be done easily with the Search Parameters. They can even be bookmarked for easy access from the main screen of the Control Panel, so a user only has to enter the query once. Good for repeat tasks or basic reporting.
Search facets
For our three-field collection, we'll define two facets which will both be text boxes, one for entering the literal ID of the listing, and the other for searching both the name and description fields. To do this, add the following to your collection definition:
[facet:id] display = ID type = text fields = id [facet:name] display = Text type = text fields = name, description
Type hints
Typehints tell the default Sitellite add and edit forms how to treat each field when shown as a MailForm widget. Using these you can change labels, widget types, and add validation rules to each field. For ours, we'll simply change the label position of the description field and add a rule that the name can't be empty. The reason we don't have to specify everything explicitly is because Sitellite knows how to determine certain characteristics from the underlying database structure in order to properly display many common types of fields.
[hint:name] rule 1 = not empty, You must enter a name for your listing. [hint:description] labelPosition = left ; */ ?>
Security tip
Notice on the first and last lines of the collection definition are the same odd looking lines found in the Objects.ini.php file as well. Because the file ends in .php, when it's requested from the server it's treated as a PHP script. So we can use these lines to prevent anyone from seeing the contents of these files, as an added bit of security-through-obscurity.
The first character of the line starts an INI-formatted comment, and then on the first line we open a PHP tag and a multiline PHP comment. On the last line we start with another INI comment, and then close the PHP comment and PHP tag. This makes all of our file contents part of a single PHP comment, which gets stripped out before being sent tot he browser.
The versioning table
Since we're going to use Sitellite's versioning capabilities on our collection, the last step before we can view our collection in action is to define the database schema for the versioning table. Enter the following into the SQL Shell of the DB Manager:
create table myapp_listing_sv (
sv_autoid int(11) not null auto_increment,
sv_author varchar(48) not null default '',
sv_action enum(
'created','modified','republished','replaced','restored','deleted','updated'
) not null default 'created',
sv_revision timestamp(14) not null,
sv_changelog text not null,
sv_deleted enum('yes','no') not null default 'no',
sv_current enum('yes','no') not null default 'yes',
id int not null,
name char(48) not null,
description text not null,
primary key (sv_autoid),
index (sv_author,sv_action,sv_revision,sv_deleted,sv_current),
index (id)
);
This table is based on our original myapp_listing table with a few changes/additions. Specifically:
- The table name has an '_sv' at the end, which signifies it's a Sitellite Versioning table.
- There are 7 new fields at the start of the table, each beginning with the 'sv_' prefix:
- sv_autoid – The unique version number
- sv_author – The username of the author of the change
- sv_action – The type of change made
- sv_revision – A timestamp of when the change was made
- sv_changelog – An optional summary of the changes provided by the author
- sv_deleted – Whether this is a deleted item or not
- sv_current – Whether this is the most current version of the item
- The primary key is now the 'sv_autoid' field, and the 'id' field is only indexed like any other.
- The other 'sv_' fields are also indexed, since they are made frequent use of.
The collection API: Meet Rex
In the same way that we used Generic to access simple database tables, we can use the Rex package to access collections. Create another box named 'rextest' and copy the access.php file from one of our other boxes into it. Then create an index.php file for the new box with the following contents:
<?php
// import rex from the cms app
loader_import ('cms.Versioning.Rex');
// create a new rex object with our collection
$rex = new Rex ('myapp_listing');
// create a new item with the create() method
$id = $rex->create (array (
'name' => 'Test',
'description' => 'Test description',
));
// output a list of items with our existing listings.spt file
echo template_simple (
'listings.spt',
$rex->getList ()
);
// delete our test item
$rex->delete ($id);
?>
If you run this box via http://www.example.com/myapp-rextest-action, you should see the test listing displayed using the listings.spt template from our previous example. As you can see, Rex makes it as easy as Generic did to access Sitellite-managed collections.
For public-facing code, which is usually more read-only in nature, Generic offers a clearer programming model for app development. Once a table uses Sitellite's versioining though, it should be managed through Sitellite itself and dynamically through the Rex libraries.
Rex is mainly used to extend Sitellite's administrative interface, with custom reporting or custom input/editing forms. For more detail on Rex and collection definitions, visit the following link:




John Luxford