Dashboard > ringside > ... > Getting Started Trail Map > Customizing with my own TAGs
Customizing with my own TAGs Log In | Sign Up   View a printable version of the current page.

Theme of this Trail
In this trail, you will learn how you can customize a Ringside Social Application Server with your own XML tag extensions that applications can use. This capability allows you to share custom functionality across all social applications deployed in your Ringside server by giving applications the ability to use your own XML tags.

Setup

All source code for this trail can be found in one of three places:

  1. [installation_dir]/apps/ringside/htdocs/trail_map_6 (if you used the Ringside installer)
  2. Download it here as either a tarball (for Linux/Mac) or a zip file (for Windows)
  3. Build it yourself. This assumes you have the Ringside source checked out from SVN. Go to your working copy's /demo-apps directory and run the build by executing phing. The source for this trail will then be located here (relative to your SVN working copy): dist\demo-apps\stack\apps\ringside\htdocs\api\trail_map_6

The Suggestions Tag Explained

At this point in this Getting Started Trail, you have developed an application, used the Ringside client to call various APIs, and developed a custom client for other applications to make use of. Wouldn't it be great to provide other application developers with an easy to use tag that supports the functionality of your application? This trail will guide you on just how to do that.

To recap, the suggestions application does primarily two things:

  1. Displays a form for making suggestions
  2. Displays topics and their associated suggestions

Writing a tag that can also serve these purposes would make it easy for other application developers to embed suggestions within their own applications. For example, an application that offers mapping or travel related functionality might want to provide users with the ability to suggest vacation destinations for their friends. In this trail, we will make this capability easy to use via a tag that looks like this:

<rs:suggestions showform="true"
                newtopics="true"
                existingtopics="false"
                topic="Great Band Names"
                ownerid="12345">
    <rs:ratings style="yesno"/>
</rs:suggestions>
  • showform: (Optional) Indicates whether this tag should render a form to add new suggestions (true) or not (false). Defaults to true.
  • newtopics: (Optional) indicates whether this tag should allow users to make suggestions for new topics or not. Defaults to true.
  • existingtopics: (Optional) indicates whether this tag should allow users to select from a list of existing topics owned by themselves or their friends. Defaults to true. If this is set to false, the topic attribute may not be set to all.
  • topic: (Optional) The topic to be displayed below the form (if present). A value of all will cause all topics owned by the logged in user or any of his friends to be displayed with the accompanying suggestions. Defaults to all. If existingtopics is set to false, this may not be set to all. In this case, new suggestions will be applied to the specified topic. The only exception to this is if newtopics is set to true and is filled in by the user.
  • ownerid: (Optional) If specified, only displays topics owned by the logged in user, even if topic is set to all or is omitted (and thus defaults to all).
  • <rs:ratings>: (Optional) If present, ratings will be enabled for each suggestion.
  • style: (Optional) Indicates the ratings style to be used. Valid options include yesno (giving the ability to rate by clicking yes or no), thumbs (providing thumbs up and thumbs down voting ability), or stars (giving the ability to rate from 1-5 stars).

Configuring Ringside

For this beta release, dynamic discovery and loading of custom tags is not implemented, thus you'll need to make two simple updates to Ringside code. Open the following file for editing, depending on how you installed your Ringside software:

In the initHandlers() function, you will need to add the following lines:

self::$handlers['fb']["rs:suggestions"]="rsSuggestionsHandler";
self::$handlers['fb']["rs:ratings"]="rsRatingsHandler";

In addition, you will need to update the parser's configuration to include your new tag. To do so, open: [installation dir]/apps/ringside/includes/ringside/social/config/dsl-tidy.conf (or, if using an SVN working copy, <trunk>/social/includes/ringside/social/config/dsl-tidy.conf)

Add the appropriate entries (as per the instructions in the comments in that file). In the case of the <rs:suggestions> tag, it should be added to the 'new-empty-tags' and 'new-blocklevel-tags' lists. The <rs:ratings> tag should be added to the 'new-empty-tags' and 'new-inline-tags' lists.

Finally, add the SuggestionClient.php and RingsideRestClient.php to your distribution by copying them to your [installation dir]/apps/ringside/includes/ringside/api/clients directory (or, if using an SVN working copy, <trunk>/WHERE SHOULD THIS BE?)

These three updates initialize your tag handler class with the Ringside Social Application Server so that when it encounters your tag, it will know how to render it.

Writing The Tag

A tag is supported by a tag handler class. When the Ringside Social Application Server encounters a tag in an application, it will lookup the handler class for that tag and call the appropriate methods on that tag at the appropriate times in order to render it.

The appropriate methods have the following signatures:

function doStartTag( $application, $parentHandler, $args );
function doBody($application, $parentHandler, $args, $body );
function doEndTag( $application, parentHandler, $args );

The parameters passed into the tag handler are as follows:

  • $application: RingsideSocialDslContext - this can be used to obtain a reference to a client which can be used to get information from the API container, such as the current user or the application ID, for example.
  • $parentHandler: A parent tag handler, if one exists.
  • $args: An array of the name/value pairs that were specified as attributes and values in the tag (as used on the page that is being rendered)
  • $body: The text that is enclosed in the body of the tag.

Note that at this time, there is not an interface defined that tag handlers must implement.

When implementing tag handlers, there are certain values that can be returned from the doStartTag() function that direct the parser, as follows:

  • true - call each child then call my doEndTag()
  • false - don't process me
  • tag names (string) - a comme-separated list of tags
  • array of tag names - ONLY process these tags
  • 'body' - says collect the body text and call the doBody() handler with the text passed in
  • 'print' - print the begin tag, then walk the children, then print end tag
  • 'redirect' - redirect to the url in the tag attributes

Now that we've described the mechanics, let's look at the doStartTag() function in our tag handler for the <rs:suggestions/> tag:

/**
 * Emits the form for submitting suggestions, as appropriate.
 */
function doStartTag( $application, &$parentHandler, $args ) {

	if( isset( $args['showform'] ) && strcasecmp( $args['showform'], 'true' ) == 0 ) {
		echo '<div class="suggest_form">';
		echo '<h3>Suggest something.</h3>';

		echo '<form method="post" action="">';
		echo '<input type="hidden" name="uid" value="'.$application->getCurrentUser().'" />';

		if( isset( $args['newtopics'] ) && strcasecmp( $args['newtopics'], 'true' ) == 0 ) {
			echo '<div class="suggest_topic_label">New Topic:</div>';
			echo '<div class="suggest_topic_input"><input type="text" name="newtopic" size="80" maxlength="80" /></div>';
			echo '<br />';
		}

		//call API to get existing suggestions for this user
		$this->loadTopicsAndSuggestions( $application  );

		// Only display options if there are existing topics in the user's social network
		if( !empty( $this->topics ) ) {
			echo '<div class="suggest_topic_label">Existing Topic:</div>';
			echo '<div class="suggest_topic_input">';
			echo '   <select name="existingtopic"><option selected="true" value="none">-</option>';
			foreach( $this->topics as $topic ) {
				echo '      <option value="' . $topic[0] . ':' . $topic[1] . '">' . $topic[1] . '</option>';
			}
			echo '   </select>';

			echo '</div>';
		}

		echo '<div class="suggest_text_label">Suggestion:</div>';
		echo '<div class="suggest_text_input"><input type="text" name="suggestion" size="80" maxlength="80" /></div>';
		echo '<br />';
		echo '<div class="suggest_submit"><input type="submit" name="submit" value="Post" /></div>';
		echo '</form>';
		echo '</div>';
	} else {
	   echo '<br /><a href="index.php">Make Suggestions</a><br />';		   
	}

	return 'rs:ratings';
}

As you can see, the doStartTag() function first checks whether the 'showform' attribute was set on the tag, and if it was set to true, in which case the form to submit new suggestions is displayed. Next, it determines whether new topics should be accepted, again using the $args parameter. Then a utility function loads topics and suggestions utilizing the SuggestionsClient (described in Trail 5), existing topics are displayed, and the rest of the suggestion form is emitted. Finally, a string is returned containing the name of the only acceptable child tag that could be parsed, <rs:ratings>. For this example, we have not implemented ratings support (this is an exercise left to the reader), so the parser will simply call doEndTag() next. Here is the code of the doEndTag() function:

function doEndTag( $application, $parentHandler, $args ) {

	$this->loadTopicsAndSuggestions( $application  );

	$lasttopic = '';

	$count = 0;
	if ( !empty( $this->suggestions) ) {
	foreach( $this->suggestions as $suggestion ) {
		$topic = $suggestion['topic'];
		try {
			$names = $application->getClient()->users_getInfo( $suggestion['uid'], "first_name" );
			$name = $names[0];
			$firstname = $name['first_name'];
		} catch( Exception $e ) {
			$firstname = 'Friend of Friend';
		}

		// Checking for topic switches
		if( $topic != $lasttopic ) {
			if( $count > 0 ) {
				echo '</table>';
			}
			echo '<br />';
			echo '<table border="0" width="500px" cellpadding="5">';
			echo '  <tr><td width="500px" colspan="2" bgcolor="#f7931d">Topic: ' . $topic . '</td></tr>';
			$lasttopic = $topic;
		}
	      
		echo '  <tr>';
		echo '      <td width="35%" bgcolor="#fdc589">' . $suggestion['suggestion'] . '</td>';
		echo '      <td width="65%" bgcolor="#eeeeee">posted by ' . $firstname . ' at ' . $suggestion['created'] . '</td>';
		echo '  </tr>';
		$count++;
	}
	}
	if ( $count > 0 ) { 
		echo '</table>';
	}
}

The doEndTag() function again loads topics and their associated suggestions, and outputs a tabular display of them.

Deployment

Currently, new tag handler classes must be created in or copied to [installation dir]/apps/ringside/includes/ringside/social/dsl/handlers/fbml/ (or, if using SVN a working copy, <trunk>/social/includes/ringside/social/dsl/handlers/fbml/).

Assuming that you've followed these steps to configure Ringside to properly recognize your tag handlers, the Ringside Social Application Server will invoke its functions when it encounters an instance of your tag.

Next Trail

Go to the next trail to learn how to deploy your applications as javascript widgets in any web page on any website.

Added by Brian Robinson , last edited by John Mazzitelli on Apr 24, 2008  (view change)
Labels: 
(None)