Polyphony
From Harmoni
Polyphony is a package that package that contains common libraries and actions that can be useful to many applications. Application-level Polyphony differs from Harmoni in that its libraries interface with the user/client-environment, as opposed to the base-services environment. An example architecture is show in the image below, with Polyphony and the application's other code above Harmoni.
Contents |
Installation
Installing requires defining two constants, (POLYPHONY_DIR and POLYPHONY_PATH) and including the main Polyphony file:
/*********************************************************
* Polyphony location
* DIR: the location on the file system
* PATH: the location as seen by the browser. For image urls.
*********************************************************/
define("POLYPHONY_DIR", "./polyphony-0.7.0/");
define("POLYPHONY_PATH", "./polyphony-0.7.0/");
/******************************************************************************
* Include Polyphony
******************************************************************************/
if (!file_exists(POLYPHONY_DIR."/polyphony.inc.php")) {
print "<h2>Polyphony was not found in the specified location, '";
print POLYPHONY_DIR;
print "'. Please install Polyphony there or change the location specifed.</h2>";
print "<h3>Polyphony is part of the Harmoni project and can be downloaded from <a href='http://sf.net/projects/harmoni/'>http://sf.net/projects/harmoni/</a></h3>";
}
require_once (POLYPHONY_DIR."/polyphony.inc.php");
JavaScript Libraries
Polyphony includes a number of JavaScript libraries to aid application development.
Common
String.replaceAll()String.urlDecodeAmpersands()String.wordWrap(maxLength, breakWith, cutWords)String.htmlSpecialChars()Array.elementExists(value)document.get_element_by_id(id)document.getOffsetLeft(element)- Answer offset of an element from the left side of the document.window.getInnerHeight()- Answer the inner height in pixels of the window in a cross-browser way.window.getInnerWidth()- Answer the inner width in pixels of the window in a cross-browser way.- Date parsing and display functions.
loadScript(url)- Add a javascript script url to the head of the document. (By Moshe Moskowitz on 06/21/2002 -- http://www.codehouse.com/javascript/articles/external/)
Harmoni
Harmoni.createRequest()- Create an XML HTTP request objectHarmoni.quickUrl(module, action, parameters, namespace)- Answer a Harmoni URL
Panel
A 'panel' in this context is an interface element that can be 'popped up' in the browser. Unlike a pop-up window, the panel is an XHTML element in the page rather than a separate window, preventing users from 'loosing' the interface element.
The basic panel has a title and configurable content area and can be centered over any particular element on the page.
The 'CenteredPanel' gets centered on the page with a translucent screen behind it, forcing the user to deal with it before resuming usage of the page.
AuthZViewer
This is a Panel-based UI for displaying the authorizations on an item.
Tagger
The Tagger is a JavaScript UI element that makes use of a Panel and provides a Tagging interface that can be attached to any item -- such as an Asset -- that has a unique Id.
Libraries
Abstract Actions
A set of abstract action classes that application actions can extend to get access to common functionality such as Wizard interaction, RSS or XML output, etc.
Action
This class is the most simple abstraction of an action. It provides a structure for common methods
Force Auth Action
The ForceAuthAction forces token collection via HTTP Authentication to allow authentication outside of the context of a browser Harmoni-Application environment. For instance, this can be used to authenticate an RSS reader for an RSS feed, or to prompt for authentication for a file that is directly linked from another website.
Main Window Action
The MainWindowAction is an abstract class that provides a standard way of setting up and executing an action in the main window of the application. It provides a structure for accessing various parts of this main window, as well as delegating the implementation of some methods to decendent classes.
RSS Action
This action abstracts the creation of RSS Feeds, providing an object-oriented approach for setting the various data properties, properly formatting RSS dates, etc.
Wizard Action
The Wizard action abstracts much of the logic for interfacing with the Wizard library and determining when to save the user-data and when to cancel.
An action that extends the WizardAction should implement the following methods:
createWizard()- Create a new Wizard object and return it. Caching of this Wizard is handled by the abstract class and does not need to be implemented here.saveWizard($cacheName)- Save our results. Tearing down and unsetting the Wizard is handled by the abstract class and does not need to be implemented here.getReturnUrl()- Return the URL that this action should return to when completed.
In its execution script the action will need to define a cache-name that identifies this instance of the wizard, allowing [if desired] the same action to create multiple instances of the wizard for each unique item that is worked with. The script will also need to pass a GUI container in which to render the Wizard:
/**
* Build the content for this action. This action will enable editing
* of a collection.
*
* @return void
* @access public
* @since 4/26/05
*/
function buildContent () {
$centerPane =& $this->getActionRows();
$repositoryId =& $this->getRepositoryId();
$cacheName = 'edit_collection_wizard_'.$repositoryId->getIdString();
// Ensure that all links and forms in the wizard pass along our
// collection_id parameter
$harmoni =& Harmoni::instance();
$harmoni->request->passthrough("collection_id");
$this->runWizard ( $cacheName, $centerPane );
}
/**
* Create a new Wizard for this action. Caching of this Wizard is handled by
* {@link getWizard()} and does not need to be implemented here.
*
* @return object Wizard
* @access public
* @since 4/28/05
*/
function &createWizard () {
...
// Instantiate the wizard, then add our steps.
$wizard =& SimpleStepWizard::withDefaultLayout();
// :: Step One ::
$stepOne =& $wizard->addStep("namedesc", new WizardStep());
$stepOne->setDisplayName(_("Name & Description"));
// Create the step text
ob_start();
$displayNameProp =& $stepOne->addComponent("display_name", new WTextField());
$displayNameProp->setValue($repository->getDisplayName());
$displayNameProp->setErrorText(_("A value for this field is required."));
$displayNameProp->setErrorRule(new WECNonZeroRegex("[\\w]+"));
print "\n<h2>"._("Name")."</h2>";
print "\n"._("The Name for this <em>Collection</em>: ");
print "\n<br />[[display_name]]";
$fieldname = RequestContext::name('description');
$descriptionProp =& $stepOne->addComponent("description", WTextArea::withRowsAndColumns(10,80));
$descriptionProp->setValue($repository->getDescription());
print "\n<h2>"._("Description")."</h2>";
print "\n"._("The Description for this <em>Collection</em>: ");
print "\n<br />[[description]]";
print "\n<div style='width: 400px'> </div>";
$stepOne->setContent(ob_get_contents());
ob_end_clean();
...
}
/**
* Save our results. Tearing down and unsetting the Wizard is handled by
* in {@link runWizard()} and does not need to be implemented here.
*
* @param string $cacheName
* @return boolean TRUE if save was successful and tear-down/cleanup of the
* Wizard should ensue.
* @access public
* @since 4/28/05
*/
function saveWizard ( $cacheName ) {
$wizard =& $this->getWizard($cacheName);
// If all properties validate then go through the steps nessisary to
// save the data.
if ($wizard->validate()) {
$properties =& $wizard->getAllValues();
...
return TRUE;
} else {
return FALSE;
}
}
XML Action
A generic action for writing XML responses.
start()- Sends the proper XML header and starts a top-level<response>element.end()- Closes the<response>element and exits.error()- Writes an<error>element with the error message and exits.
Basket
The basket is a package that provides shopping cart-like functions without the implication of purchasing. It allows users to carry around references to a bunch of items and make use of them elsewhere.
Hierarchy Printer
A library for displaying an expandable hierarchy of items.
Result Printer
A library for printing a paginated result-set from either an array or an Iterator.
Repository Importer
A library for importing Assets into a Repository
Repository Input/Output Modules
Libraries for creating, updating, and viewing Asset data elements.
StartupCheck
The StartupCheck package in Polyphony allows you to automate, with the use of "requirement modules", the process required by most web applications to check system resources and requirements, and run autonomous (those not requiring user input) or non-autonomous updates/installations. The StartupCheck package is useful in the following areas, including others
- Checking for the presence of PHP modules/extensions
- Checking for required versions of PHP or other programs
- Checking for existence of database tables (and creating them if necessary)
- Automating the process of first-time-run configuration; ie, setting up preferences, adding users, etc.
- Checking for required php.ini configuration values.
The following sections of this manual will detail the usage of this package.
Basic Usage
There are two main ways to use the StartupCheck package: either in conjunction with the PHP session handler (suggested), or run every pageload. We will explain here how to use it with the session handler, as using it without is just simplifying the same process. The following code will check to make sure that the version of Harmoni we are using is at least 0.2.0, that register_globals and magic_quotes_gpc are off, and that we have the PHP extension gettext installed. The class files for these pre-installed requirements can be found in polyphony/main/library/StartupCheck/CommonRequirements.
In the above block of code, the first section first checks to see if the session variable __startupCheck has been defined, and if not, it creates a new StartupCheck object and stores it in the session. Next, it adds a number of requirements via the addRequirement() function. The first parameter is just a unique name that you assign to the requirement. The second is a class that implements the StartupRequirement interface (the file can be found in polyphony/main/library/StartupCheck/StartupRequirement.interface.php). The StartupRequirement is where all the action occurs. By changing what StartupRequirements you add to the StartupCheck class, you can control how the startup/update/install process of your program goes. The next sections will concentrate on the creation of these StartupRequirement classes.
The second section of the code above tells the StartupCheck class to go through all of the requirements and check their status, update them if necessary, and ask for user input if that's needed as well. The handleAllUpdates() method takes the Harmoni object as its paramter and returns true if everything's up-to-date or if things were updated on their own. It will return false if either something went wrong or if user input is needed. If the latter is the case, then the StartupCheck class outputs an HTML page asking for the required information, so your program should halt execution to let the user enter information.
StartupRequirements
The StartupRequirement interface is pretty simple. It requires that your class have only four methods
-
getDisplayName()- returns a string with the display name of this requirement. -
getStatus()- returns an integer which describes the status of the requirement. A number of constants have been defined to use here, which are outlined below. -
createWizard()- returns a Wizard object containing an interface for user input, if the requirement requires user input. -
doUpdate([$properties])- returns an integer describing the new status of the requirement after updating. If the requirement needed user input, an array of WizardProperty objects is passed.
A requirement's status is described by one of the following constants:
-
STARTUP_STATUS_OK- everything is A-OK. -
STARTUP_STATUS_ERROR- this means that an error occured that can't be fixed. This should, hopefully, never happen. -
STARTUP_STATUS_NEEDS_UPDATE- the requirement needs to run an autonomous update to be satisfied. -
STARTUP_STATUS_NEEDS_USER_INPUT- the requirement needs user input before an update can be performed. In this case, StartupCheck will call the createWizard() method on the requirement. -
STARTUP_STATUS_NOT_CHECKED- used internally by the StartupCheck class - specifies that the status of the requirement hasn't even been checked. -
STARTUP_STATUS_NEEDS_INSTALL- the requirement needs to run an autonomous install to be satisfied. This is essentially synonymous withSTARTUP_STATUS_NEEDS_UPDATE.
For more information on creating new StartupRequirements, take a look at the classes in the folder polyphony/main/library/StartupCheck/CommonRequirements.
Tagging
A library for interacting with Tags that are stored in the Harmoni Tagging system. The Tagging library generates tag clouds, displays tagged items, and uses the JavaScript Polyphony#Tagger Tagger UI to apply tags to items.
Wizard
An extensive library for creating multi-step Wizard UIs.
Modules
The modules included with Polyphony are ones that are common to most of the applications that we develop. Instead of adding them to each application individually, the Polyphony modules directory can be added as a modules-location to be searched by the Harmoni ActionHandler.
Many of the Polyphony libraries listed above also have associated modules used for displaying UIs and/or doing data processing. The modules listed here are those additional modules that do not have a library component.
Agent
UIs for managing Agents and Groups.
Authentication
These are some simple actions for login, failed-login, and logout.
Below is one example of some code that could be put on a page to access the login actions.
// Login links
print _("Current User: ");
// If they are logged in, print their name and a logout link
if ($harmoni->LoginState->isValid()) {
print $harmoni->LoginState->getAgentName();
print " - <a href='".MYURL."/auth/logout/".
implode("/", $harmoni->pathInfoParts)."'>";
print _("Log Out");
// Otherwise, print a login link
} else {
print _("anonymous");
print " - <a href='".MYURL."/auth/login/".
implode("/", $harmoni->pathInfoParts)."'>";
print _("Log In");
}
print "</a>";
Authorization
UIs for browsing and modifying authorizations.
EXIF
Includes an action which will display the EXIF data for an image, useful for determining what data is available for importing.
Export
Actions for exporting Repositories and Assets.
Help
A contextual help system.
Language
The language.change action changes the current action and returns the user to their previous action.
Put the following on your pages to submit the language change:
// Define the form and language-selection field
print "\n<form action='".MYURL."/language/change/"
.implode("/", $harmoni->pathInfoParts)."' method='post'>";
print "\n\t<select name='language'>";
// Get a list of the availible languages.
$langLoc =& Services::getService('Lang');
$currentCode = $langLoc->getLanguage();
$languages = $langLoc->getLanguages();
ksort($languages);
// Print out an option for each language.
foreach($languages as $code => $language) {
print "\n\t\t<option value='".$code."'"
.(($code == $currentCode)?" selected='selected'":"").">";
print $language."</option>";
}
// Close up the form.
print "\n\t</select>";
print "\n\t<input type='submit'>";
print "\n</form>";
Logs
Includes actions for viewing and searching logs, as well as actions that provide RSS feeds of logs.
User
Includes a 'change password' action.


