< Calling Plugins

Dynamic mapfile modifications >

2. New Plugins

2.1.  What are Plugins

2.1.1. Definition

CartoWeb plugins are modular packages of files (PHP classes, HTML templates, images and other resources) that are used to perform a dedicated action: main map formatting, layers browsing interface, map browsing (zooming, paning etc.), queries, user authentication, search interfaces and many more.

2.1.2. Plugins and Coreplugins

There are two kinds of plugins:

  • coreplugins: fundamental plugins that perform "low-level" actions such as map size handling, browsing tools, layers selection. Plugins that are frequently used in many CartoWeb applications may be included in this category as well. They are always available and activated. As a result, other plugins may interact with them. Coreplugins files are grouped in the coreplugins/ directory.
  • plugins: "normal" plugins perform more specificactions and are not always activated. Normal plugins activation is done by setting the loadPlugins parameter in client_conf/client.ini for CartoClient plugins and in server_conf/<mapId>/<mapId>.ini for CartoServer ones. For instance:
    loadPlugins = auth, outline, exportHtml
           
    Since they are not always available, simple plugins usually do not rely on each other. On the other hand, it is not a problem for them to call some coreplugins functionalities if the latter are publicly accessible. Simple plugins files are grouped in the plugins/ directory.

The general philosophy is to gather all files of a given plugin in the same dedicated directory, including files from both CartoClient and CartoServer sides of the plugin. Thus it is easy to "plug" a new module in CartoWeb architecture by simply pasting it in the plugins/ or coreplugins/ parent directories. Note however that plugins configuration files (named <pluginName>.ini) are placed in the client_conf/ and/or server_conf/<mapId>/ depending if those plugins have CartoClient/CartoServer components.

2.1.3. Plugins Structure

Plugins and coreplugins have the following general structure:

<pluginName>/
<pluginName>/client/
<pluginName>/server/
<pluginName>/common/
<pluginName>/templates/
<pluginName>/htdocs/
<pluginName>/htdocs/gfx/
<pluginName>/htdocs/js/
<pluginName>/htdocs/css/

  • client/ contains all specific CartoClient-side PHP files.
  • server/ contains all specific CartoServer-side PHP files.
  • common/ contains PHP files shared by both CartoClient and CartoServer sides, or at least files that are not specific to one side or the other.
  • templates/ contains all the plugin-specific Smarty templates. Since HTML templates are only used in CartoClient, files from templates/ are only called by client/ code.
  • htdocs/ contains all files (PHP pages, images, JavaScript or CSS files, etc.) that may be web-accessed when running the plugin. Those files are dispatched in various directories depending on their nature. If necessary, you can create additional subdirectories. For instance java/ if your plugin uses a Java applet. To preserve the plugin independence, it is strongly recommended not to add your CSS styles in the general CartoClient style sheet but to create a specific file here that will be called separately.

Note that it is not required to actually create the whole structure described above. Only directories that contain files are necessairy. For instance if a plugin only perform CartoServer actions, it is no use to create client/, templates/ and htdocs/ directories. common/ may be usefull if not-CartoServer-specific classes have to be defined.

There are two ways to add a plugin/coreplugin to CartoWeb: writing a brand new one or overriding/extending an existing one.

2.2. Writing a Plugin

2.2.1. Introduction

If no existing plugin or coreplugin fulfils your requirements and if none offers close enough functionalities to justify an adaptation, you can write a new plugin.

Plugins main classes (client and/or server if any) must extend CartoWeb definedClientPlugin and/or ServerPlugin classes which provide base plugin tools. For instance:

class ClientYourPlugin extends ClientPlugin {

    /* here comes your plugin client class definition */

}

2.2.2. Plugin or Coreplugin?

First of all you have to determine if you are about to design a simple plugin or a coreplugin. To be a coreplugin, your plugin must be really generic and present a great interest to the CartoWeb users community since it might be included in the upstream distribution. Contact CartoWeb development team for more info. In most cases it is better and sufficient to create a simple plugin.

To activate a coreplugin, update the Cartoclient::getCorePluginNames() method in /client/Cartoclient.php and/or the ServerContext::getCorePluginNames() one in /server/ServerContext.php. For instance:

private function getCorePluginNames() {
return array('images', 'location', 'layers', 'query', 'mapquery',
             'tables', 'yourPluginName');
}

To load a regular plugin, update the loadPlugins parameter from client_conf/client.ini and/or server_conf/<mapId>/<mapId>.ini as in following example:

loadPlugins = auth, outline, exportHtml
      

2.2.3. How Plugins Are Called

As explained in Section 2.1, “ What are Plugins”, plugins are independent aggregations of PHP code that are called by the CartoWeb core classes to perform dedicated actions. Plugins are called several times during the program execution (entry points). Thus they can interact at various level of the application.

To determine what plugins must be called at what moment and to perform what action, plugins must implement one or more of the CartoWeb plugin interfaces (according to the object-oriented programing meaning). The interfaces define methods that will be triggered by the main program during its execution. For example, you can take a look at the following simplified Cartoclient::doMain() method ("main program") defined in /client/Cartoclient.php:

private function doMain() {
    $this->callPluginsImplementing('InitUser', 'handleInit',
                                   $this->getMapInfo());

    if ($this->isRequestPost()) {
        $this->cartoForm =
            $this->httpRequestHandler->handleHttpRequest(
                                                $this->clientSession,
                                                $this->cartoForm);

        $request = new FilterRequestModifier($_REQUEST);
        $this->callPluginsImplementing('FilterProvider',
                                       'filterPostRequest', $request);
        $this->callPluginsImplementing('GuiProvider',
                                       'handleHttpPostRequest',
                                       $request->getRequest());
    } else {
        $request = new FilterRequestModifier($_REQUEST);
        $this->callPluginsImplementing('FilterProvider',
                                       'filterGetRequest', $request);
        $this->callPluginsImplementing('GuiProvider',
                                       'handleHttpGetRequest',
                                       $request->getRequest());
    }

    $mapRequest = $this->getMapRequest();
    $this->callPluginsImplementing('ServerCaller', 'buildRequest',
                                   $mapRequest);

    $this->mapResult = $this->getMapResultFromRequest($mapRequest);

    $this->callPluginsImplementing('ServerCaller', 'initializeResult',
                                   $this->mapResult);

    $this->callPluginsImplementing('ServerCaller', 'handleResult',
                                   $this->mapResult);

    $this->formRenderer->showForm($this);

    $this->callPluginsImplementing('Sessionable', 'saveSession');
    $this->saveSession($this->clientSession);
}

callPluginsImplementing($interfaceName, $methodName, $argument) is run at various points of the program and make plugins implementing given <interfaceName> interface execute given <methodName> with given <argument> argument.

Of course interface-defined methods must be implemented in the matching plugins. Plugins can implements one or more CartoWeb interfaces.

Implementing interfaces is not mandatory when writing a plugin but not doing so will keep plugins from being implicitely called by the main program. As a result, methods from plugins with no interface implementation - also called "service plugins" - must be explicitely called by another piece of code (generally an other plugin).

class ClientYourPlugin extends ClientPlugin 
                       implements Sessionable, GuiProvider {

    /* here comes your plugin client class definition */

}

For a comprehensive list of available client and server interfaces, see /client/ClientPlugin.php and /server/ServerPlugin.php files or take a look at the CartoWeb PHP API documentation.

Diagram of CartoWeb plugins interfaces and methods calls

(Get a high quality version of this diagram here.)

2.2.4. Plugin Creation Check-List

  1. Determine if you will write a plugin or a coreplugin.
  2. Create a <yourPlugin>/ directory in /projects/<yourProject>/plugins/ if you need a simple plugin. Directory name will be the plugin name. You can use whatever name you want except of course names of already existing plugins or coreplugins. Yet it is recommended to use lowercase letters, capitalizing only the first letter of each word that composes the name (eg. "yourPluginName"). In case of a coreplugin, there is no way to create a coreplugin in a project context. Coreplugins can only be integrated in the upstream application. It is not recommended to do so without CartoWeb developers agreement because of compatibility troubles that may occur when upgrading, etc.
  3. Create subdirectories to store all plugin-related resources files and templates.
  4. Create client/, server/, common/ if your plugin as CartoClient, CartoServer and respectively common parts.
  5. Create your main PHP classes files. Those files must be named using the first-letter-capitalized name of your plugin, prefixing it with "Client" or "Server" for client or server components (eg. ClientYourPlugin.php, ServerYourPlugin.php, YourPlugin.php).
  6. Extend ClientPlugin and/or ServerPlugin CartoWeb classes in the matching above files and name the result classes using their files names (with no ".php"). For instance:
    <?php
    /**
     * @version $Id: ServerYourPlugin.php,v 1.8 2005/02/23 11:52:43 johndoe Exp $
     */
    
    class ServerYourPlugin extends ServerPlugin {
    
    
  7. Make your classes implement needed interfaces and redefine corresponding methods. Note that the common/ part class "YourPlugin" does not have to extend or implement any CartoWeb class or interface. It is used as a container for common data and treatment used by client and server classes.
  8. If your plugin is implementing ServerCaller and ClientResponder, you will need to write the WSDL code for the plugin request and response. See Section 2.1, “ What are Plugins” for examples on how to write such WSDL documents.

    Note

    You need to add a className element in the WSDL file for a proper parsing from CartoWeb

  9. Activate your plugin by adding its name to the loadPlugins of the matching project configuration files.

2.2.5. Automatic Files Inclusion

Main plugin PHP files (eg. ClientYourPlugin.php, ServerYourPlugin.php, YourPlugin.php) are automatically included and their contained classes and objects are directly accessible. Other files in client/, server/ or common/ are not and must be included explicitely in the main plugin PHP files.

Templates stored in the plugin templates/ directory are also accessible directly by using PHP code similar to the followin one:

$smarty = new Smarty_Plugin($this->getCartoclient(), $this);
$smarty->assign('foo', 'bar');
return $smarty->fetch('yourPlugin.tpl');

2.3. Adapting a Plugin

2.3.1. Approaches

If an already available plugin or coreplugin offers close functionalities to the ones you need, if you wish to slightly modify its behavior or simply want to adapt its output to your website layout, it is far easier to adapt it then to build a new one from scratch.

There are two levels of plugin adaptation. You can:

  • override its HTML templates, resources (pictos, CSS or JS files) and its configuration as well. This approach is generally sufficient when you only need to adapt the layout.
  • extend the main PHP classes to add your own methods or overload existing ones. This approach is required when you need to add some PHP code to the plugin.

Both approaches are not incompatible and may be combined to obtain desired result. See Section 2.3.4, “Combining Both Approaches” for more explanations.

2.3.2. Overriding a Plugin

Overriding a plugin is the simplest way to adapt it to your needs. It is done by duplicating the plugin files (at least the ones you want to adapt) in your project frame. For more information about projects handling, see Section 2.4, “Projects”.

This approach is recommended when you want to use your own versions of the plugin templates or resources. Moreover you can add any new resources files that will be called in your customized templates. However you will not be able to replace or add PHP files (except PHP pages in the plugin htdocs/. To adapt a plugin server-side behavior (PHP classes), you have to extend the plugin, which is explained in Section 2.3.3, “Extending a Plugin”.

Say for instance, you want customize the layers coreplugin by modifying its template layers.tpl and rewriting some of its JS tools (stored in layers.js). Than your project-adapted coreplugin will look like:

/projects/<yourProjectName>/coreplugins/layers/
/projects/<yourProjectName>/coreplugins/layers/templates/
/projects/<yourProjectName>/coreplugins/layers/templates/layers.tpl
/projects/<yourProjectName>/coreplugins/layers/htdocs/
/projects/<yourProjectName>/coreplugins/layers/htdocs/js/
/projects/<yourProjectName>/coreplugins/layers/htdocs/js/layers.js
      

If you don't need to override the CSS file, it is no use to create a css/ directory containing a copy of the upstream layers.css.

If you want to neutralize a file, you can simply override it with a blank version. For instance to have a void output, create a template file with no content.

It is also possible to override the plugin configuration files by adding <pluginName>.ini files in the project configuration directories client_conf/ and/or server_conf/<mapId>/. When the plugin is launched, upstream and project configuration files are merged so you don't need to duplicate the configuration parameters that stay unchanged with your adapted plugin.

2.3.3. Extending a Plugin

Extending a plugin is required when your adaptations involve deep changes such as additions or overloadings of methods in the plugin PHP classes.

To do so you will have to extend the plugin PHP classes in the object-oriented programing definition. Since plugin main classes are named using a plugin-name based convention (eg. ClientLayers and ServerLayers for the CartoClient and CartoServer main classes of the layers coreplugin) and since extended classes cannot have the same name than their parent class, you will have to rename your plugin. Any plugin name is OK (as long as it is not already used!) but it is recommended to use a <projectName><initialPluginName> separating words with caps.

Extended coreplugins directories and files must be saved in /projects/<projectName>/coreplugins/<extendedPluginName>/ whereas extended simple plugins ones will be located in /projects/<projectName>/plugins/<extendedPluginName>/.

When writing your extended class, the first thing to do is to specify what plugin is replaced by the new one. This is done by overloading the replacePlugin() method. It should return the replaced plugin name. For instance, to extend the layers coreplugin CartoClient part in your myProject project, create a ClientMyProjectLayers.php as follows:

<?php
/**
 * @package CorePlugins
 * @version $Id: ClientMyProjectLayers.php,v 1.8 2005/02/23 11:52:43 johndoe Exp $
 */

class ClientMyProjectLayers extends ClientLayers {

    public function replacePlugin() {
        return 'layers';
    }

    /* Add or overload methods here */
    
}
?>

To be activated, extended plugins AND coreplugins must be explicitely be declared in the loadPlugins parameter of your project general configuration files:

loadPlugins = exportPdf, auth, myProjectLayers
      

With no surprise, extended classes can take advantage of the tools provided by the interfaces their parent classes implement. By implementing additional interfaces, they will have access to complementary interactions as well. In that case, don't forget to overload the matching interface-defined methods in your extended class. For instance:

ClientMyProjectLayers extends ClientLayers
                      implements ToolProvider {

/* ... */

}

Tip

To use new config parameters in your extended plugin, add them in the .ini file of your project original plugin (eg. /projects/<your_project>/client_conf/<original_plugin>.ini).

2.3.4. Combining Both Approaches

If you need to modify/add templates or resources (overrriding) AND PHP classes (extension), you can combine both approaches by following the instructions of the two last sections.

Say you would like to customize the images coreplugin (mainmap size and formats management) to:

  • update the layout (new pictos, new texts, new CSS),
  • add some JS processing,
  • add a new form field in a separated area of the CartoWeb interface.

First point is achieved by creating a images/ directory in /projects/yourProject/coreplugins/ and filling it with an overriden template mapsizes.tpl, a new images.css and some pictos:

/projects/yourProject/coreplugins/images/
/projects/yourProject/coreplugins/images/templates/mapsizes.tpl
/projects/yourProject/coreplugins/images/htdocs/css/images.css
/projects/yourProject/coreplugins/images/htdocs/gfx/button.png
      

<!-- mapsizes.tpl -->
<p>{t}Mapsize:{/t}
<select name="mapsize" id="mapsize" onchange="javascript:checkMapsize();">
{html_options options=$mapsizes_options selected=$mapsize_selected}
</select>
<input type="image" src="{r type=gfx plugin=images}button.png{/r}"
alt="{t}Ok button{/t}" id="imagesButton" /></p>

For details about template {r} (resource) and {t} (translation) tags, see Section 18.2, “Internationalization” and Section 18.3, “Resources”.

checkMapsize() JavaScript function is not defined in the upstream coreplugin. So we have to add a JS file in our overriden plugin:

/projects/yourProject/coreplugins/images/htdocs/js/
/projects/yourProject/coreplugins/images/htdocs/js/images.js
      

/* images.js */

function checkMapsize() {
  alert('foobar');
}

To add a new form field in a separated area and consequently in a separated template, there is no other way than to modify the ClientImages PHP class in order to call the additional template in a special method. The extension approach is thus required. Then create a yourProjectImages/ directory in /projects/yourProject/coreplugins/ as follows:

/projects/yourProject/coreplugins/yourProjectImages/
/projects/yourProject/coreplugins/yourProjectImages/client/
/projects/yourProject/coreplugins/yourProjectImages/client/ClientYourProjectImages.php
      

It can seem a little tricky but the new template file (say yourImages.tpl) will not be stored in /projects/yourProject/coreplugins/yourProjectImages/templates/ as one can expect it but in /projects/yourProject/coreplugins/images/templates/ with the templates of the "overriden part" of the coreplugin. Remember: templates are stored in the overriden part and PHP classes in the extended part.

<!-- yourImages.tpl -->

<input type="text" name="testField" value="{$imagesTest}" />
      

<?php
/**
 * @version $Id: ClientYourProjectImages.php,v 1.8 2005/02/23 11:52:43 johndoe Exp $
 */

class ClientYourProjectImages extends ClientImages {

    // indicates that we want to use current plugin instead of 
    // regular images plugin
    public function replacePlugin() {
        return 'images';
    }

    // overloaded method
    public function renderForm(Smarty $template) {
        // a {$image2} Smarty var must have been added in cartoclient.tpl
        $template->assign('image2', $this->drawNewImagesField());
        parent::renderForm($template);
    }

    // additional method
    private function drawNewImagesField() {
        $smarty = new Smarty_Plugin($this->getCartoclient(), $this);
        $smarty->assign('imagesTest', 'Foobar');
        return $smarty->fetch('yourImages.tpl');
    }
}
?>

Don't forget to activate the extended plugin in /projects/yourProject/client_conf/client.ini:

loadPlugins = yourProjectImages
      

2.4. Special Plugins

2.4.1. Export Plugins

Export plugins allow to export maps and data. Concepts described below provide tools to help writing such plugins.

In brief, export plugins follow these steps in order to generate an output:

  • Retrieve last request that was sent to server
  • Call all plugins to ask for request modification (eg. map resolution changes, keymap generation enabled/disabled, etc.)
  • Call server to get a new modified result
  • Use the result to generate output
  • Return output in a standardized form

2.4.1.1. Export Plugin Naming Convention

Warning

Export plugins MUST have names that begin with the string "export", for instance exportPdf, exportCsv or exportHtml.

This rule does not apply to extended plugins since only the original plugin name is detected.

2.4.1.2.  ExportPlugin

Class ExportPlugin implements a special type of client plugin, with some specific functionnalities for export. It implements interface GuiProvider so child classes must implement corresponding methods. Class methods are:

  • getLastMapRequest: returns last used request object. This is useful to prepare a new call to server in order to obtain data specific to export. This call is done in method getExportResult
  • getLastMapResult: This can also be useful in some cases to have the last returned result obect
  • getExportResult: executes call to server in order to obtain a modified result suitable for export generation. Calls all exportable plugins in order to modify request (see Section 2.4.1.4, “Exportable Interface”)
  • getExport (abstract): contains export generation itself. Should prepare export configuration, call getExportResult and generate export in an ExportOutput object

2.4.1.3.  ExportConfiguration

Export configuration objects contain information on what is needed by export plugin to generate output. For instance, for a CSV export, no images are needed and it would be a waste of time to generate them.

Configuration is set in method getExport, then passed to method getExportResult in order to get modified result. Configuration is used by plugin to know how to modify request to retrieve useful data.

2.4.1.4. Exportable Interface

Exportable interface declares a method adjustExportMapRequest which modifies a standard map request to a special export request. For instance, plugin Image uses ExportConfiguration object to know if maps are needed by export plugin. If not, image request is modified.

2.4.1.5. Example

Plugin exportCsv is a good, simple example of export plugin.

Configuration is filled in method getConfiguration. No images are required to output a CSV file:

protected function getConfiguration() {
    $config = new ExportConfiguration();
    $config->setRenderMap(false);
    $config->setRenderKeymap(false);
    $config->setRenderScalebar(false);
}

Result rendering is done in method getExport. Note that no calls to methods getLastMapRequest or adjustExportMapRequest are needed, as those calls are handled by method getExportResult:

protected function getExport() {
    $this->getExportResult($this->getConfiguration());
    
    // ...
    
    $output = new ExportOutput();
    $output->setContents($contents);
    return $output;
}

Final output (headers + content) is done in method output. For instance:

public function output() {
    header('Content-Type: text/html');
    print $this->getExport()->getContents();
    return '';
}

2.4.2. Filters

Filter plugins can be used to modify parameters transfered from browser to CartoWeb client. These parameters can be part of a POST request (HTML forms) or a GET request (URL query string).

Once a new filter plugin has been developed, it can be activated by adding it to the loadPlugins variable in file client_conf/client.ini.

2.4.2.1. Interface and Classes

Interface FilterProvider declares following methods:

  • filterPostRequest(FilterRequestModifier $request): modifies parameters transfered via a POST request
  • filterGetRequest(FilterRequestModifier $request): modifies parameters transfered via a GET request

Class FilterRequestModifier is used to get old values from the request and set new ones. It implements two main methods:

  • getValue($key): retrieves old value
  • setValue($key, $value): sets new value

2.4.2.2. Available Parameters

This is the list of global parameters accepted by CartoWeb via GET

  • reset_session : This will reset all session parameters to default value. Useful when you want to go back to the initial stats of the application
        http://www.yoursite.org/cartoweb3/htdocs/client.php?reset_session
                  
  • prevent_save_session : This will bypass the session save. Useful when you want to performe an action without effect on the actual state of the application. This was added specifically when using the mode=image global parameter
        http://www.yoursite.org/cartoweb3/htdocs/client.php?prevent_save_session
                  
  • force_map_refresh : This will force the map to be redrawn by Mapserver, effectively removing all cache.
        http://www.yoursite.org/cartoweb3/htdocs/client.php?force_map_refresh
                  

    Warning

    This may impact performances and load. It's adviced to only use it for development purpose.

  • mode : This will define the kind of output of CartoWeb. By default it will be html. Another possible output is image. In this case, CartoWeb will only output an image.
        http://www.yoursite.org/cartoweb3/htdocs/client.php?mode=image
                  
    The image mode can be used with other plugin specific parameters:
        http://www.yoursite.org/cartoweb3/htdocs/client.php?mode=image&recenter_x=300000&recenter_y=5150000&recenter_scale=150000
                  

This is the list of parameters that can be set in a filter plugin using function setValue() (in php file) or GET request (URL query string):

  • Images plugin
    • mapsize - ID of the selected map size (see Section 8.1, “ Client-side Configuration ”)
    • customMapsize - this string parameter enables to specify a customized map size using the syntax [width]x[height], [width] and [height] being positive integers (size in pixels). You may specify dimensions limitations in client_conf/images.ini (see Section 8.1, “ Client-side Configuration ”)
    • drawMainmap - boolean indicating if the mainmap must be drawn or not.
    • drawKeymap - boolean indicating if the keymap must be drawn or not.
    • drawScalebar - boolean indicating if the scalebar must be drawn or not.
  • Location plugin
    • recenter_bbox - new bounding box, comma-separated coordinates, eg. "10.5,20,15.5,28"
    • recenter_x - re-centering: new x-coordinate
    • recenter_y - re-centering: new y-coordinate
    • show_crosshair - '0' or '1', default '0'. If '1' display a crosshair on (recenter_x, recenter_y).
    • recenter_scale - new scale
    • id_recenter_layer - re-centering on objects: layer to look for IDs
    • id_recenter_ids - re-centering on objects: list of IDs, comma-separated
    • shortcut_id - ID of the selected map size (see Section 7.2, “Server-side Configuration”)

    Warning

    A layer must be queryable before id recentering works! Add TEMPLATE "ttt" to that layer in the mapfile.

  • Query plugin
    • query_layer - layer to look for IDs
    • query_select - IDs of objects to add to selection
    • query_unselect - IDs of objects to remove from selection
    • query_policy - selection policy: 'POLICY_XOR', 'POLICY_UNION' or 'POLICY_INTERSECTION', default is 'POLICY_XOR'
    • query_maskmode - '0' or '1', default is '0'. If '1', will show selection as a mask.
    • query_hilight - '0' or '1', default is '1'. If '0', won't shows selection hilighted.
    • query_return_attributes - '0' or '1', default is '1'. If '0', won't return attributes other than IDs.
    • query_return_table - '0' or '1', default is '1'. If '0', won't return any table results.
    • query_clear - '0' or '1', default is '0'. If '1', previous query results are purged even if they were marked as persistent.
    • query_blocks - an "associative array" parameter used to select objects from several layers at once. Indexes are layers ids whereas values are ids of objects to query. For instance query_blocks[layer1] = 123,345,358&query_blocks[layer2]=4,2345,98. When this parameter is used, query_select and query_unselect parameters are ignored.
  • Layers plugin
    • switch_id - id of the switch to be used when the children switching is activated (see Section 6.2.4, “Children Switching”).
    • layer_select - comma-separated list of layers or layerGroups id's that must be added into the activated layers list.
    • layer_unselect - comma-separated list of layers or layerGroups id's that must be removed from the activated layers list. In some cases, layerGroups children might have to be explicitely listed to actually be removed.
  • Outline plugin

Warning

Note that for Query plugin, display of extended selection must be disabled in client's query.ini in order to use above parameters (see Section 9.1, “Client-side Configuration”).

Tip

To make CartoWeb outputs a map as a raw image file (no HTML generated), you may use the GET parameter mode=image. For instance:

http://example.com/cartoweb3/client.php?mode=image&mapsize=2

2.4.2.3. Example

The following class implements a filter which allows to recenter on an object while hilighting it:

class ClientFilterIdrecenter extends ClientPlugin
                             implements FilterProvider {
                       
    public function filterPostRequest(FilterRequestModifier $request) {}
    
    public function filterGetRequest(FilterRequestModifier $request) {
        
        $id = $request->getValue('id');
        if (!is_null($id)) {
            $layer = 'grid_classhilight';
            $request->setValue('query_layer', $layer);
            $request->setValue('query_maskmode', '1');
            $request->setValue('query_select', $id);

            $request->setValue('id_recenter_layer', $layer);        
            $request->setValue('id_recenter_ids', $id);
        }
    }
}

2.4.3. Tables

Tables plugin is responsible for table formatting and display.

2.4.3.1. Tables Structures

Tables plugin declares several structures to help plugin developer manage tables. These structures are:

  • Class Table which includes in particular a list of rows (class TableRow)
  • Class TableGroup which includes in particular a list of tables. Table groups are used for instance to separate table results coming from several plugins
  • Class TableFlags which defines parameters that will be useful for a plugin using tables

Typically, a plugin using table will include a TableFlags in its request and a TableGroup in its result. This is the case for Query plugin, which is the only core plugin which uses tables.

2.4.3.2. Setting Rules

Tables plugin maintains an object called the registry (one on client and one on server). This object allows to add table rules, which will describes how tables must be displayed.

It is recommended to add rules in plugin's initialize() method, so they are ready at the earliest stage. To obtain the registry object, first you have to get the Tables plugin object.

On client:

public function initialize() {

    $tablesPlugin = $this->cartoclient->getPluginManager()->tables; 
    $registry = $tablesPlugin->getTableRulesRegistry();
    
    // Add rules here
}

On server, plugin manager is stored in ServerContext object:

    // ...
    $tablesPlugin = $this->serverContext->getPluginManager()->tables;        
    // ...

Now you are ready to add rules. Next sections describe the different types of rules. Registry's method signature is explained for each type.

Once rules have been added in registry, they must be executed on tables. See Section 2.4.3.4, “Executing Rules” for a description of table rules execution.

2.4.3.2.1. Column Selector
public function addColumnSelector($groupId, $tableId, $columnIds) 
          

Column selector rules allow to keep only a subset of columns from the source table. Parameter $columnIds should contain an array of column IDs determining which columns to keep.

2.4.3.2.2. Column Unselector
public function addColumnUnselector($groupId, $tableId, $columnIds) 
          

Column unselector rules allow to keep only a subset of columns from the source table, by removing a list of columns. Parameter $columnIds should contain an array of column IDs determining which columns to remove.

2.4.3.2.3. Group Filter
public function addGroupFilter($groupId, $callback)

Group filter rules allow to modify group title. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('group_id', 'group_title')
    return 'group_new_title' 
2.4.3.2.4. Table Filter
public function addTableFilter($groupId, $tableId, $callback) 
          

Table filter rules allow to modify table title. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id', 'table_title')
    return 'table_new_title' 
2.4.3.2.5. Column Filter
public function addColumnFilter($groupId, $tableId,
                                $columnId, $callback)

Column filter rules allow to modify column title. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id', 'column_id', 'column_title')
    return 'column_new_title'
2.4.3.2.6. Cell Filter
public function addCellFilter($groupId, $tableId, $columnId,
                              $inputColumnIds, $callback)

Cell filter rules allow to modify content of a cell. Values of columns given in parameter $inputColumnIds will be transfered to the callback method for cell content calculation. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id', 'column_id',
                                 array ('column_1' => 'value_1',
                                        'column_2' => 'value_2'))
    return 'cell_value'

Note

To return all column's data to the callback function, you can use NULL.

        $registry->addCellFilter('query', 'table_name', '*', NULL,
                   array('TableRulesClassName', 'callbackFunctionName'));        
        

This will apply the callbackFunctionName function to all column of table table_name and the callback function will receive an array containing the values of all columns.

2.4.3.2.7. Cell Filter (Batch)
public function addCellFilterBatch($groupId, $tableId, $columnId,
                                   $inputColumnIds, $callback) 
          

Cell filter rules used in batch mode allow to modify content of all cells of a given column. Values of columns given in parameter $inputColumnIds will be transfered to the callback method for cells content calculation. Values for all rows are transfered at the same time. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id', 'column_id',
                                 array (
                                 '0' => array (
                                        'column_1' => 'value_1_row_1',
                                        'column_2' => 'value_2_row_1'),
                                 '1' => array (
                                        'column_1' => 'value_1_row_2',
                                        'column_2' => 'value_2_row_2')))
    return array ('0' => 'cell_value_row_1', '1' => 'cell_value_row_2') 
          
2.4.3.2.8. Row Unselector
public function addRowUnselector($groupId, $tableId,
                                 $columnId, $rowIds)

Row unselector rules allow to remove some rows from a table. Parameter rowIds contains IDs of row that must be removed.

2.4.3.2.9. Row Selector
public function addRowSelector($groupId, $tableId,
                                 $columnId, $rowIds)

Row selector rules allow to keep only some rows from a table. Parameter rowIds contains IDs of row that must be kept.

2.4.3.2.10. ColumnAdder
public function addColumnAdder($groupId, $tableId,
                               $columnPosition, $newColumnIds,
                               $inputColumnIds, $callback)

Column adder rules allow to add one or more columns to the table. Parameter $newColumnIds should contain the list of new column IDs. Values of columns given in parameter $inputColumnIds will be transfered to the callback method for cell content calculation. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id',
                                 array ('column_1' => 'value_1',
                                        'column_2' => 'value_2'))
    return array ('new_column_1' => 'cell_value_1',
                  'new_column_2' => 'cell_value_2')

Parameter $columnPosition indicates where the new columns must be inserted. It should be an instance of class ColumnPosition. Positions can be absolute or relative, with a positive or negative offset:

  • $position = new ColumnPosition(ColumnPosition::TYPE_ABSOLUTE, 1); 
                  
    The new columns will be added after the first column
  • $position = new ColumnPosition(ColumnPosition::TYPE_ABSOLUTE, -2); 
                  
    The new columns will be added just before the last column
  • $position = new ColumnPosition(ColumnPosition::TYPE_RELATIVE,
                                   0, 'column_1'); 
    The new columns will be added just before column 'column_1'
  • $position = new ColumnPosition(ColumnPosition::TYPE_RELATIVE,
                                   1, 'column_1'); 
    The new columns will be added just after column 'column_1'
2.4.3.2.11. Column Adder (Batch)
public function addColumnAdderBatch($groupId, $tableId,
                                    $columnPosition, $newColumnIds,
                                    $inputColumnIds, $callback) 
          

Column adder rules used in batch mode allow to add one or more columns to the table, while calculating values for all newly added cells. Parameter $newColumnIds should contain the list of new column IDs. Values of columns given in parameter $inputColumnIds will be transfered to the callback method for cells content calculation. Values for all rows are transfered at the same time. Parameter $callback should contain a pointer to a callback method with the following signature:

static function myCallbackMethod('table_id',
                                 array (
                                 '0' => array (
                                        'column_1' => 'value_1_row_1',
                                        'column_2' => 'value_2_row_1'),
                                 '1' => array (
                                        'column_1' => 'value_1_row_2',
                                        'column_2' => 'value_2_row_2')))
    return array (
           '0' => array (
                  'new_column_1' => 'cell_value_1_row_1',
                  'new_column_2' => 'cell_value_2_row_1'),
           '1' => array ( 
                  'new_column_1' => 'cell_value_1_row_2',
                  'new_column_2' => 'cell_value_2_row_2')))

See Section 2.4.3.2.10, “ColumnAdder” to know more about parameter $columnPosition.

2.4.3.2.12. Column reorder
public function addColumnReorder($groupId, $tableId, $columnIds)
        

Column reorder rule allow you to reorder the columns and their contents. Parameter $columnIds should contain an array of column IDs given the new column's order. Note that all the IDs must appear in $columnIds even they don't move.

2.4.3.3. Precedence of Rules

Depending on rule type, rules are set for a group, a table or a column. Parameters ($groupId, $tableId or $columnId) can point to one object or to a group of object, using wildcard '*':

  • 'column_1': rule will be executed on columns called 'column_1' only
  • 'col*': rule will be executed on columns with name starting with 'col'
  • '*': rule will be executed on any columns

For instance, following rule may be executed on groups with name starting with 'myGr', tables called 'myTable' and all columns:

$registry->addColumnFilter('myGr*', 'myTable', '*',
                                     array($this, 'myCallbackMethod)); 
        

Only one rule of each type may be executed on one item. If two or more rules apply, most specific rule will be choosen. In the following rule definition, only the third rule will be executed on a table 'myTable' in a group 'myGroup':

 
$registry->addColumnSelector('*', '*', array('column_1', 'column_2'));
$registry->addColumnSelector('myGr*', '*', array('column_1'));
$registry->addColumnSelector('myGr*', 'myTable', array('column_2'));
$registry->addColumnSelector('myGroup', 'toto', array('column_3')); 
        

2.4.3.4. Executing Rules

2.4.3.4.1. On Client

Each time a table group is created, it must be stored in Tables plugin in order to display it:

$tablesPlugin = $this->cartoclient->getPluginManager()->tables;
$tablesPlugin->addTableGroups($newTableGroup);

Tables rules are executed automatically at the same time.

2.4.3.4.2. On Server

Rules execution must be done explicitly on server. A call to Tables plugin applyRules method is needed for each new table group before returning it to client:

$tablesPlugin = $this->serverContext->getPluginManager()->tables;
readyForClientTableGroups = $tablesPlugin->applyRules($newTableGroup); 
          
valid xhtml 1.0 valid css