Creating a complete web application with PoolParty

This technical note will show how to create a complete, usable web application using the PoolParty API. This example shows how to extend the functionality of one part of PoolParty out to an external application.

A number of my clients have asked whether it is possible to allow users in the organisation to suggest new taxonomy concepts. Being able to capture the ideas of people who may not be professional taxonomists is an important part of good taxonomy design and governance. At the same time, it's important for good governance to ensure that taxonomy development is managed effectively, by experts. These seem like incompatible goals, but in this application I'm building an interface that will allow us to do just that.

The key is to use PoolParty suggestions. A PoolParty suggestion is a kind of pending concept; a logged-in user can offer a suggestion through the PP Browser interface. That suggestion is not actually created as a real concept until a PoolParty administrator approves it. So the background to this application is a need to have an alternative interface through which any user can suggest a new concept, with the administrator subsequently approving or declining the suggestion.

Some small print before we start

I am not a software developer, and I'm not offering this application as professional quality code. I'm showing it simply to give an example of how to construct an API method, how to submit it to the PoolParty server and how to handle the response data.

A walk-through

Let's start with a walk-through of the finished application. The suggestions demonstrator is a one-page application that shows two pieces of information; a table containing a collection of the current suggestions, and a form through which to suggest a new concept. The first figure below shows how the application looks at the point where a user has loaded it.

On load the application uses an API method to make a call to PoolParty requesting the concept suggestions available for the relevant project. There is already one pending suggestion in place. The user has completed the form (with Pinot noir as the preferred label and an appropriate supporting note) and is about to submit it.

On submission the application collects up the data in the form and uses another PoolParty method to send the suggestion. After submission the page reloads, with the new suggestion visible and the form cleared for a new submission.

That's about it for the application user interface. Now let's look at what has happened in PoolParty. As an administrator I have access to a workflow dashboard. When I load that I see a list of the concept suggestions. I can choose to accept one or more suggestions and choose where in the taxonomy hierarchy it belongs.

 

The code

The application is written in PHP (like I say, I'm not a developer, but most IT folks can at least write something in PHP!). This section goes through the application in detail and describes what is happening at each step. At the end of this note there will be a complete listing with embedded comments.

At the top of the code I'm including the Httpful library. This is a freely-available library of PHP code for RESTful client applications. You can find the library here: http://phphttpclient.com

<?php
    include('./httpful.phar');

Next, I needed to set up some variables; the url of the PoolParty server, the project id for the project and the authentication details. You'll need to provide your own data here of course. The project id can be found in the PoolParty UI. Choose the top level of the taxonomy and the id will appear below the project title. For this example I have a taxonomy called "Wimsey Wines", which is intended to hold concepts about wine; this project has the id 1DF124F7-FF3E-0001-A893-A6BDFE0A1353.

    $ppserver = 'http://tellura.poolparty.biz';
    $projectid = '1DF124F7-FF3E-0001-A893-A6BDFE0A1353';

For authentication, you may wish to specify a special api user with no roles but membership of all necessary groups. See the developer documentation:

    $user = 'apiuser';
    $pw = 'your-password';

Next, I checked to see whether there was anything in the POST array. In PHP, this is the key to a one-page application. The application has a form, and on submission loads the same page again, with the POST array holding the data that was previously in the web form. If the user has just POSTed anything in the form then the application processes the data, otherwise it just needs to load and show any existing information (more on this later).

    if(isset($_POST['newsuggestion'])) {

If there is POST data, pick up the concept label and note from the POST array.

        $suggestionPrefLabel = $_POST['newsuggestion'];
        $suggestionNote = $_POST['noteforsuggestion'];

Next, I run a function that sends off the request to add a suggestion. The return value is the generated URI of this concept suggestion. We are just using this to give a message back to the user in the HTML below.

        $newConceptURI = createNewSuggestion($suggestionPrefLabel, $suggestionNote);

    } else {

        // Nothing posted, so no need to do anything. The HTML table below will show any existing suggestions

    }

 

That's the end of the if clause, so at this stage we've either run the query and got a response, or we don't need to run a query (because the POST array is empty).

Either way, the next step is to use the REST API to get a list of current concept suggestions in PoolParty.

    $suggested_concepts = getSuggested();

Next we work through the functions. The first is createNewSuggestion. This assembles the API request, sends it off and retrieves a response.

    function createNewSuggestion($suggestionPrefLabel, $suggestionNote) {

I used the PHP global function to make sure the connection variables are in scope.

        global $ppserver, $projectid, $user, $pw;

Next I defined the PoolParty API method that we need to use, and then used it to assemble the request.

        $cmdAddSuggestion = 'suggestConcept';

        $request2 = $ppserver . '/PoolParty/api/thesaurus/' . $projectid . '/' . $cmdAddSuggestion;

Now I define the payload and send off the request - note that it's a POST and we need to add a content type header.

The payload should look like this:
{
"prefLabels": [ { "label":"****preLabel goes here****", "language":"en" } ],
"checkForDuplicates" : true,
"note" : "****note goes here"
}
You can supply additional parameters here. See the documentation page for more: https://help.poolparty.biz/doc/developer-guide/basic-advanced-server-api...

        $payload = '{ "prefLabels": [ { "label":"' . $suggestionPrefLabel . '", "language":"en" } ],"checkForDuplicates" : true,    "note" : "' . $suggestionNote . '" }';


        $response2 = \Httpful\Request::post($request2)

                ->sendsJson()

                ->addHeader('Content-Type', 'application/json')

                ->authenticateWith($user, $pw)

                ->body($payload)

            ->send();

PoolParty API responses in PHP applications are generally PHP objects that contain arrays. There may be several levels of this structure.
You can use the var_dump command to inspect the response object:
It looks like this: echo var_dump($nameOfTheVariable);
For this example I just want the [body] member from the response object, so echo var_dump($concepts_array["body"]); is the command we want.
This gives us this data:
object(stdClass)#9 (1) { ["uri"]=> string(81) "http://[your-server]/[your-taxonomy]/[concept-suggestion-id]" }

For this example I've unpacked it in a step by step manner. It's possible to collapse the next four lines into one.
Anyway, here goes: first I cast the response object to an array.

        $concepts_array = (array)$response2;

Extract the body member from the array.

        $conceptArrayBody = $concepts_array["body"];

The body member is another object, so cast this to an array.

        $conceptURIarray = (array)$conceptArrayBody;

Extract the URI member from this array $conceptURIdata = $conceptURIarray[uri];

Finally, the function return the arrays - this ends up in $newConceptURI in the calling method and in the HTML below.

        return $conceptURIdata;

    }

The second function gets the current set of suggestions.

    function getSuggested() {

        global $ppserver, $projectid, $user, $pw;

This time we need the suggestedConcepts API method.

        $cmd_getsuggested = 'suggestedConcepts';

        $request = $ppserver . '/PoolParty/api/thesaurus/' . $projectid . '/' . $cmd_getsuggested;

Next I sent off the request. This time it's a simpler GET request.

        $response = \Httpful\Request::get($request)

            ->authenticateWith($user, $pw)

        ->send();

Now I have a response object as a json package. I need to unpack it to nice php arrays and variables that I can do something useful with!

Cast the response object to an array.

        $suggested_concepts_array = (array)$response;

Get the "body" member out of the array.

        return $suggested_concepts_array["body"];

    }
?>

This is the end of the processing code. The HTML and PHP code below displays the form and the list of concept suggestions.

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="utf-8" />

        <!-- Use online Bootstrap CSS and JavaScript libraries -->

        <!-- Latest compiled and minified CSS -->

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

        <!-- Optional theme -->

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

        <!-- Latest compiled and minified JavaScript -->

        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>    <title>Add and show suggestions</title>

    </head>

    <body>

        <?php if(isset($_POST['newsuggestion'])) { ?>

        <div class='container'>

            <div class='alert alert-success'>

                <?php echo "Your new concept suggestion with preferred label <strong>" . $suggestionPrefLabel . "</strong> and URI <strong>" . $newConceptURI . "</strong> was submitted to PoolParty."; ?>

            </div>

        </div>

        <?php } ?>

        <div class='container'>

            <h1>Tellura Semantics concept suggestion demo</h1>

            <p>This application shows how to add suggestions for new concepts into a PoolParty installation. Use the boxes below to suggest a new concept.</p>

        </div>

        <div class='container'>

            <form role="form" action="<?php echo $_SERVER['PHP_SELF']; ?>" method='POST'>

                <div class='form-group'>

                    <div class='input-group'>

                        <div class='row'>

                            <p>&nbsp;</p>

                        </div>

                    </div>

                    <div class='row'>

                        <p>&nbsp;</p>

                    </div>

                    <div class='row'>

                        <div class='col-sm-8'>

                            <input class='form-control' placeholder='Write the preferred label for your suggestion here' type="text" name="newsuggestion" />

                            <input class='form-control' placeholder='Add a note here if you want to' type='text-area' name='noteforsuggestion' />

                            <span class='input-group-btn'>

                                <button class='btn btn-default'>Add new suggestion</button>

                            </span>

                        </div>

                    </div>

                </div>

            </form>

        </div>

        <div class='container'>

        <h2>Current suggestions</h2>

        <p>This is the current list of suggested concepts proposed for the <strong>Wimsey Wines</strong> taxonomy.</p>

        <table class="table table-striped table-bordered">

            <?php $i=1;?>

            <thead>

                <tr>

                    <th>#</th>

                    <th>URI</th>

                    <th>Suggested concept preferred label</th>

                    <th>Notes</th>

                </tr>

            </thead>

              <tbody>

              <?php

To populate the table, start with the suggested_concepts array and loop over it.

                foreach ($suggested_concepts as $concept) {

The project data is in a PHP object, so cast it to an array.

                    $suggested_data = (array)$concept;

Unpack the uri object into its array.

                    $uri_data = (array)$suggested_data[uri];

Unpack the prefLabels data into an array - needs two steps.

                    $prefLabels_data = (array)$suggested_data[prefLabels];

                    $prefLabels_label_data = (array)$prefLabels_data[0];

                ?>

                <tr>

                  <td><?php echo $i; ?></td>

                  <td><?php echo $uri_data[uri]; ?></td>

                  <td><?php echo $prefLabels_label_data[label]; ?></td>

                  <td><?php echo $suggested_data[note]; ?></td>

                </tr>

                <?php

                ++$i;

                }

                ?>

            </tbody>

        </table>

        </div>

    </body>

    </html>

 

Complete code listing

To use this code, create a new text file with the filename suggestion-demo.php. Copy the code below and paste it into your new file. Edit the code so that it uses your PoolParty server, project and authentication information. You should then be able to run it within the context of your website.

 

<?php
/*
    #################################
        This program allows a user to suggest new concepts
        for a PoolParty taxonomy.
        
        Tested with the RESTful API of PoolParty v6.2.0
        
        Ian Piper
        Tellura Information Services
        20180516
        Copyright  Tellura Semantics - All rights reserved
    #################################
*/
    // include the restful client library. If the httpful.phar file isn't in the folder with this script, download it
    include('./httpful.phar');

    // Set up variables for use in functions
    // The PoolParty repository base URI - REPLACE THIS WITH YOUR SERVER DETAILS
    $ppserver = 'http://tellura.poolparty.biz';

    // Project id - REPLACE THIS WITH YOUR PROJECT DETAILS
    $projectid = '1DF124F7-FF3E-0001-A893-A6BDFE0A1353';
    
    /* Authentication - REPLACE THIS WITH YOUR USER DETAILS
    You should specify a special api user with no roles but membership of all necessary groups
    See the developer docs: 
    https://help.poolparty.biz/doc/administrator-guide/poolparty-administration/poolparty-user-administration/setup-an-api-user-for-poolparty
    */

    $user = 'apiuser';
    $pw = 'apiuser-password-goes-here';

/*
    #################################
    Check whether the POST array has something in it. If it has, then we have come here via a click on the form button.
    In this case, there is probably work to do. The text in the 'newsuggestion' array member is used to provide the 
    prefLabel for the PoolParty concept, and optionally the user can submit an explanatory note.
    #################################
*/

    if(isset($_POST['newsuggestion'])) {
        // We have data in the post array, so do something with it

        // Get the suggested concept label and note from the POST array
        $suggestionPrefLabel = $_POST['newsuggestion'];
        $suggestionNote = $_POST['noteforsuggestion'];
         
        // Use the REST API command to create a new concept suggestion.
        // The return value is the generated URI of this concept suggestion.
        // We are just using this to give a message back to the user.
        $newConceptURI = createNewSuggestion($suggestionPrefLabel, $suggestionNote);
    } else {
        // Nothing posted, so no need to do anything. The HTML table below will show any existing suggestions
    }

    // Use the REST API to get a list of current concept suggestions in PoolParty
    $suggested_concepts = getSuggested();

/*
    #################################
    Functions
    #################################
*/

    function createNewSuggestion($suggestionPrefLabel, $suggestionNote) {
        // make sure the connection variables are in scope
        global $ppserver, $projectid, $user, $pw;

        // This is the PoolParty API method that we need to use
        $cmdAddSuggestion = 'suggestConcept';

        // Assemble the request
        $request2 = $ppserver . '/PoolParty/api/thesaurus/' . $projectid . '/' . $cmdAddSuggestion;

        // Send off the request - note that it's a POST and we need to add a content type header

        /*
        The payload should look like this:
        { 
            "prefLabels": [ { "label":"****preLabel goes here****", "language":"en" } ],
          "checkForDuplicates" : true,
          "note" : "****note goes here"
        }
        You can supply additional parameters here. See the documentation page for more:
        https://help.poolparty.biz/doc/developer-guide/basic-advanced-server-apis/thesaurus-ontology-manager-api/thesaurus-services/suggested-concepts-services/web-service-method-suggest-concept
        */
        $payload = '{ "prefLabels": [ { "label":"' . $suggestionPrefLabel . '", "language":"en" } ],"checkForDuplicates" : true,    "note" : "' . $suggestionNote . '" }';

        $response2 = \Httpful\Request::post($request2)
                ->sendsJson()
                ->addHeader('Content-Type', 'application/json')
                ->authenticateWith($user, $pw)
                ->body($payload)
            ->send();

        // PoolParty API responses in PHP applications are generally 
        // PHP objects that contain arrays
        // There may be several levels of this structure
        // You can use the var_dump command to inspect the response object:
        // echo var_dump($nameOfTheVariable);
        // For this example I just want the [body] member from the response object
        // So echo var_dump($concepts_array["body"]); is the command we want
        // This gives us this data:
        // object(stdClass)#9 (1) { ["uri"]=> string(81) "http://[your-server]/[your-taxonomy]/[concept-suggestion-id]" }
        // For this example I've unpacked it in a step by step manner
        // It's possible to collapse the next four lines into one
        // Anyway, here goes
        // Cast the response object to an array
        $concepts_array = (array)$response2;
        // echo var_dump($concepts_array["body"]);
        // Extract the body member from the array
        $conceptArrayBody = $concepts_array["body"];
        // The body member is another object, so cast this to an array
        $conceptURIarray = (array)$conceptArrayBody;
        // Extract the URI member from this array
        $conceptURIdata = $conceptURIarray[uri];
        
        // Return the array - this ends up in $newConceptURI in the calling method and in the HTML below
        return $conceptURIdata;
    }

    function getSuggested() {
        // make sure the connection variables are in scope
        global $ppserver, $projectid, $user, $pw;
        // This time we need the suggestConcepts API method
        $cmd_getsuggested = 'suggestedConcepts';
        $request = $ppserver . '/PoolParty/api/thesaurus/' . $projectid . '/' . $cmd_getsuggested;

        // Send off the request - see the website for Httpful library for details: http://phphttpclient.com
        $response = \Httpful\Request::get($request)
            ->authenticateWith($user, $pw)
        ->send();

        // We have a response object as a json package. Now need to unpack it to 
        // nice php arrays and variables that we can do something useful with!

        // Cast the response object to an array
        $suggested_concepts_array = (array)$response;

        // Get the "body" member out of the array
        return $suggested_concepts_array["body"];
    }
    
    // This is the end of the processing code. The HTML and PHP code below displays the form and the list of concept suggestions.    
    ?>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <!-- Use online Bootstrap CSS and JavaScript libraries -->
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>    <title>Add and show suggestions</title>
    </head>
    <body>
        <?php if(isset($_POST['newsuggestion'])) { ?>
        <div class='container'>
            <div class='alert alert-success'>
                <?php echo "Your new concept suggestion with preferred label <strong>" . $suggestionPrefLabel . "</strong> and URI <strong>" . $newConceptURI . "</strong> was submitted to PoolParty."; ?>
            </div>
        </div>
        <?php } ?>
        <div class='container'>
            <h1>Tellura Semantics concept suggestion demo</h1>
            <p>This application shows how to add suggestions for new concepts into a PoolParty installation. Use the boxes below to suggest a new concept.</p>
        </div>
        <div class='container'>
            <form role="form" action="<?php echo $_SERVER['PHP_SELF']; ?>" method='POST'>
                <div class='form-group'>
                    <div class='input-group'>
                        <div class='row'>
                            <p>&nbsp;</p>
                        </div>
                    </div>
                    <div class='row'>
                        <p>&nbsp;</p>
                    </div>
                    <div class='row'>
                        <div class='col-sm-8'>
                            <input class='form-control' placeholder='Write the preferred label for your suggestion here' type="text" name="newsuggestion" />
                            <input class='form-control' placeholder='Add a note here if you want to' type='text-area' name='noteforsuggestion' />
                            <span class='input-group-btn'>
                                <button class='btn btn-default'>Add new suggestion</button>
                            </span>
                        </div>
                    </div>
                </div>
            </form>
        </div>
        <div class='container'>
        <h2>Current suggestions</h2>
        <p>This is the current list of suggested concepts proposed for the <strong>Wimsey Wines</strong> taxonomy.</p>
        <table class="table table-striped table-bordered">
            <?php $i=1;?>
            <thead>
                <tr>
                    <th>#</th>
                    <th>URI</th>
                    <th>Suggested concept preferred label</th>
                    <th>Notes</th>
                </tr>
            </thead>
              <tbody>
              <?php 
              // start with the suggested_concepts array and loop over it
                foreach ($suggested_concepts as $concept) {
                    // The project data is in a PHP object, so cast it to an array
                    // unpack the object into an array
                    $suggested_data = (array)$concept;
                    // unpack the uri object into its array
                    $uri_data = (array)$suggested_data[uri];
                    // unpack the prefLabels data into an array - needs two steps
                    $prefLabels_data = (array)$suggested_data[prefLabels];
                    $prefLabels_label_data = (array)$prefLabels_data[0];
                ?>
                <tr>
                  <td><?php echo $i; ?></td>
                  <td><?php echo $uri_data[uri]; ?></td>
                  <td><?php echo $prefLabels_label_data[label]; ?></td>
                  <td><?php echo $suggested_data[note]; ?></td>
                </tr>
                <?php 
                ++$i;
                } 
                ?>
            </tbody>
        </table>
        </div>
    </body>
    </html>