Exposed methods
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
Making methods of controllers available (optionally to other components) by exposing them, can be used to provide:
- a public method through a standard PHP or JavaScript interface
- a Callback being used internally by other components (for example by the ViewGenerator)
- a
command
-mode command accessible as a CLI command (to be used as CronJob) or HTTP endpoint that returns data in a standardized format - a DataSource with dynamic data (non-model) which can be exposed as a RESTful API endpoint
Expose a controller's 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. EitherPlain
orJson
(recommended) -
<adapterName>
is the name your controller'sgetName()
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 ifstatus
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
andflag2
- 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. |