Exposed methods

From Cloudrexx Development Wiki
Jump to: navigation, search

Controller methods can be exposed to other components through HTTP, CLI and as a DataSource. This article describes how to do that.

Note: This documentation refers to version 5 or newer. For older versions of Cloudrexx, please refer to JsonData V3/4.

Use cases

Important: Exposed methods should only be used by the controller layer. If you need to expose models, then do use the RESTful API.

Making methods of controllers available (optionally to other components) by exposing them, can be used to provide:

Expose a controller's method

Note: the following used naming (of the registering method getControllersAccessableByJson() and the implementing interface \Cx\Core\Json\JsonAdapter) might suggest that this does provide some sort of a JSON interface. Even though this is true to a certain degree, as the exposed methods are in fact accessible internally to other components through a JSON-like interface, it is in no way limited to that. Yet, the naming of the method and the interface have not (yet) been changed to describe the functionality of exposed methods in a more generic way.

To expose one controller's method, two things are needed. First, the controller must be registered as a controller that does expose methods. This is done by adding the controller's name to the return list of method getControllersAccessibleByJson() of the Component's ComponentController. I.e. to register a controller named ViewGeneratorJsonController as a controller that exposes methods, you would extend the method ComponentController::getControllersAccessibleByJson() as follows:

/**
 * @{inheritdoc}
 */
public function getControllersAccessableByJson() {
    return array(
        'ViewGeneratorJsonController'
    );
}

Second, the controller (this would be ViewGeneratorJsonController from the example above) needs to implement the interface \Cx\Core\Json\JsonAdapter which requires you to implement the following methods:

  • getName()
  • getAccessableMethods()
  • getDefaultPermissions()
  • getMessagesAsString()Deprecated

getName()

This method must return a system-wide unique name to identify this controller. This name will be referred to as the adapterName. Therefore you should simply call it by your Component's name or at least prefix it with it.

The base Controller class (\Cx\Core\Core\Model\Entity\Controller) from which your controller ultimately inherits from does already implicitly declare a getName() method through the magic method __call(). Since this is not a real method definition you need to implement the method getName() anyway, otherwise the interface definition (of \Cx\Core\Core\\JsonAdapter) will not be satisfied.

Example to use the Component's name as your adapterName:

/**
 * Returns the internal name used as identifier for this adapter
 * @return String Name of this adapter
 */
public function getName() {
    return parent::getName();
}

getAccessibleMethods()

This method must return a list of public method names to expose. Each entry can be in one of two forms:

  • Non-associative: Simply a name of a public method
  • Associative: Name of the public method as key, a Permission object as value

Methods are only available to users that fulfill the requirements specified by the passed Permission object. If no Permission object is specified the default permission is used.

Example

The following example assumes that the controller does implement a public method named getNews():

/**
 * Returns an array of method names accessable from a JSON request
 * @return array List of method names
 */
public function getAccessableMethods() {
    return array('getNews');
}

getDefaultPermissions()

This method should return a Permission object which is used if no method-specific permission-requirements are set (through getAccessibleMethods()). If this method returns null, then the default values of the Permission class constructor are used.

Example for making the exposed methods public (no access protection) by default:

/**
 * Returns default permission as object
 * @return Object
 */
public function getDefaultPermissions() {
    return new \Cx\Core_Modules\Access\Model\Entity\Permission(
        ['http', 'https'],
        ['get', 'post'],
        false,
    );
}

getMessagesAsString()

Deprecated This should return a list of success or informational messages meant for the caller. They are split by <br />.

Returning messages this way is deprecated (see subsection on new proper way) and will be replaced in a later version. So it is advised to implement this just as a dummy method as follows:

/**
 * Returns all messages as string
 * @return String HTML encoded error messages
 */
public function getMessagesAsString() {
    return '';
}

Return error-state and -message

In order to return an error state and an according message the called method should to throw an exception with the message as its message.

Call an exposed method

For a better understanding, the following placeholders will be used by the examples below:

  • <outputModule> is the selected output format. Either Plain or Json (recommended)
  • <adapterName> is the name your controller's getName() method returns
  • <methodName> is the name of the (exposed) method to invoke
  • <params> see passing params

As a HTTP endpoint

Exposed methods can be reached using the following URL scheme:

/api/Data/<outputModule>/<adapterName>/<methodName>[<params>]

In contrary to the Plain output module, which does just return the raw result of the executed exposed method, the output module Json does return the result of the executed exposed method encapsulated in a JSON-object having the following properties:

  • status: "success" or "error"
  • message: Message as string, separated by HTML BR tags.
  • data: Data returned by the method. Only set if status is "success"

Using the Contrexx Javascript Framework

cx.ajax(
    "<adapterName>",
    "<methodName>",
    {
        // normal jQuery.ajax() options
        data: {
            <params>// additional parameters to pass to the ''JsonData's'' method
        },
        success: function(json) {
            // handle response
            json.status; // "success" or "error"
            json.message; // Message as string, separated by HTML BR tags.
            json.data; // Data returned by the method. Only set if "status" is "success"
        }
    }
);

Internally from other components

Exposed methods can be accessed from other components using \Cx\Core\Json\JsonData():

$jsonData =  new \Cx\Core\Json\JsonData();
$response = $jsonData->data(
    '<adapterName>',
    '<methodName>',
    <params>
);
$response['status']; // "success" or "error"
$response['message']; // Message as string, separated by HTML BR tags.
$response['data']; // Data returned by the method. Only set if "status" is "success"

As a CLI command

Exposed methods can be accessed using the following command:

./cx Data <outputModule> <adapterName> <methodName>[ <params>]

This returns the data exactly like the HTTP endpoint variant.

As a DataSource

Not yet implemented. See \Cx\Core\DataSource\Model\Entity\JsonDataSource class.

Params

Receiving params in your method

If an exposed method is called a single argument is passed to it:

array(
    'get' => array(), // params passed to this method
    'post' => array(), // data passed to this method
)

Your method needs to be able to receive an array as its first (and only) argument.

Passing params

There are 3 types of params that can be passed:

  • Flags
  • Key/value pairs
  • Key/value pairs of data

These can be combined in a single call as necessary.

The following table shows how to pass the following params:

  • Flags: flag1 and flag2
  • Key/value pairs: "alice"=>"bob" and "foo"=>"bar"
  • Key/value pairs of data: "alice"=>"bob" and "foo"=>"bar"
Param type Access method Example
Flags HTTP endpoint
/api/Data/<outputModule>/<adapterName>/<methodName>/flag1/flag2
Internal call
$response = $jsonData->data(
    '<adapterName>',
    '<methodName>',
    array(
        'get' => array(
            'flag1',
            'flag2',
        ),
    )
);
CLI
./cx Data <outputModule> <adapterName> <methodName> flag1 flag2
DataSource endpoint Not yet implemented. See \Cx\Core\DataSource\Model\Entity\JsonDataSource class.
Key/value pairs HTTP endpoint
/api/Data/<outputModule>/<adapterName>/<methodName>?alice=bob&foo=bar
Internal call
$response = $jsonData->data(
    '<adapterName>',
    '<methodName>',
    array(
        'get' => array(
            'alice' => 'bob',
            'foo'=>'bar',
        ),
    )
);
CLI
./cx Data <outputModule> <adapterName> <methodName> alice=bob foo=bar
DataSource endpoint Not yet implemented. See \Cx\Core\DataSource\Model\Entity\JsonDataSource class.
Key/value pairs of data HTTP endpoint
POST /api/Data/<outputModule>/<adapterName>/<methodName>
 
 alice=bob&foo=bar
Internal call
$response = $jsonData->data(
    '<adapterName>',
    '<methodName>',
    array(
        'post' => array(
            'alice' => 'bob',
            'foo' => 'bar',
        ),
    )
);
CLI
echo 'alice=bob&foo=bar' | ./cx Data <outputModule> <adapterName> <methodName>
DataSource endpoint Not yet implemented. See \Cx\Core\DataSource\Model\Entity\JsonDataSource class.