JsonData

From Cloudrexx Development Wiki
Jump to: navigation, search

JsonData is a gateway to adapters which are generating JSON encoded data.

Idea

All JSON data will be handled in a central processing controller (JsonData), so it is easy to e.g. add safety measures only in one controller.

Usage

JsonData is a way to expose methods to the outside world. This can be used for AJAX requests or callbacks. For API-like cases you should use the RESTful API.

The method JsonData->data() (and JsonData->jsondata() too) will return data in the following structure (data() as an associative array, jsondata() as JSON object):

array(
    'status' => 'success'|'error',
    'message' => $msg,
    ['data' => $data,]
);

Implement a JsonAdapter

Contrexx 3.1 and newer

A JsonAdapter is a controller of a Component that implements \Cx\Core\Json\JsonAdapter and is registered as a Controller exposed to JsonData.

Step 1: Create adapter

Create a new controller in the component's controller directory: <your_component_directory>/Controller/Json<object_name>Controller.php (i.e. /modules/DemoModule/Controller/JsonDemoModuleController.php)

The adapter (/controller) must fulfill the following requirements:

  • Adapter must be in same Namespace as its component (i.e. \Cx\Modules\DemoModule\Controller)
  • Adapter must implement the Interface \Cx\Core\Json\JsonAdapter
  • Adapter must extend Cx\Core\Core\Model\Entity\Controller
  • Methods that shall be accessible using the JsonData AJAX interface must be listed in the array that is returned by the method getAccessableMethods()
    • The return type of those methods (accessible by the JsonData AJAX interface) must be an Array

Check out the following JsonAdapter example (i.e. of file /modules/DemoModule/Controller/JsonDemoModuleController.php):

<?php

/**
 * JSON Adapter for DemoModule
 * @copyright   your company
 * @author      your name <your-email-address>
 * @package     contrexx
 * @subpackage  module_DemoModule
 */

namespace Cx\Modules\DemoModule\Controller;

/**
 * JSON Adapter for DemoModule
 * @copyright   your company
 * @author      your name <your-email-address>
 * @package     contrexx
 * @subpackage  module_DemoModule
 */
class JsonDemoModuleController extends \Cx\Core\Core\Model\Entity\Controller implements \Cx\Core\Json\JsonAdapter {
    
    /**
     * Returns the internal name used as identifier for this adapter
     * @return String Name of this adapter
     */
    public function getName() {
        return parent::getName();
    }
    
    /**
     * Returns an array of method names accessable from a JSON request
     * @return array List of method names
     */
    public function getAccessableMethods() {
        return array('getData');
    }

    /**
     * Returns all messages as string
     * @return String HTML encoded error messages
     */
    public function getMessagesAsString() {
        return '';
    }
    
    /**
     * Returns an array containing some data
     * @return array Array containing data
     */
    public function getData() {
        // add some data to $arrData that you would like to return through the JsonAdapter
        $arrData = array('data' => 'Hello World');
        return $arrData;
    }
}
Step 2: Register JsonAdapter

The JsonAdapter must be registered by the component's ComponentController using the method getControllersAccessableByJson(). Please keep in mind that every controller needs to be registered as a controller using getControllerClasses().

Check out the following example for a component's ComponentController (i.e. of file /modules/DemoModule/Controller/ComponentController.class.php):

<?php
/**
 * Main controller for DemoModule
 * 
 * @author your name <your-email-address>
 * @package contrexx
 * @subpackage module_DemoModule
 */

namespace Cx\Modules\DemoModule\Controller;

/**
 * Main controller for DemoModule
 * 
 * @author your name <your-email-address>
 * @package contrexx
 * @subpackage module_DemoModule
 */
class ComponentController extends \Cx\Core\Core\Model\Entity\SystemComponentController {

    public function getControllersClasses() {
        return array(
            'JsonDemoModule',
        );
    }

    public function getControllersAccessableByJson() {
        return array(
            'JsonDemoModuleController',
        );
    }
}

Contrexx 3.0.x

A JsonAdapter must fulfill the following requirements:

  • The adapter is located in /core/Json/Adapter/{Component}/Json{Object}.php (e.g. /core/Json/Adapter/ContentManager/JsonNode.php)
  • The adapter is located in the namespace \Cx\Core\Json\Adapter\{Component} (e.g. \Cx\Core\Json\Adapter\ContentManager\JsonNode)
  • The adapter implements the interface \Cx\Core\Json\JsonAdapter
  • The adapters are listed in a static array: \Cx\Core\Json\JsonData::$adapter_classes

A JsonAdapter should fulfill the following requirements:

  • It returns an array which does not return JSON objects, JsonData will convert it recursively
    • If this is not so, the method \Cx\Core\Json\JsonData->data() will not return useful output

A JsonAdapter can use the following things:

  • Methods, which are not in the array (returned by getAccessibleMethods()) and which are not accessible via JsonData

Return error-state and -message

  • To return an error state and an according message, the adapter has to throw a new Exception with the message as Exception message.

Get data from adapter

From JavaScript

Through JsonData AJAX Interface

The JsonData adapters (as implemented in section Implement a JsonAdapter) can be accessed using the following JavaScript code:

cx.ajax(
    "$nameOfJsonAdapter",
    "$methodNameOfJsonAdapter",
    {
        // normal jQuery.ajax() options
        data: {
            // additional parameters to pass to the JsonData's method
        },
        success: function(json) {
            // handle response
        }
    }
);
Variable Description Example
$nameOfJsonAdapter The name of the JsonData-Adapter. This must be the same value as the one that is returned by the method getName() of the JsonAdapter. DemoModule
$methodNameOfJsonAdapter The method name of the JsonData-Adapter that shall be called getData
Example for the JsonDemoModule adapter defined in above section Implement a JsonAdapter

Execute the following JavaScript code from within the Backend:

cx.ajax(
    "DemoModule",
    "getData",
    {
        // normal jQuery.ajax() options
        data: {
            // additional parameters to pass to the JsonData's method
        },
        success: function(json) {
            // handle response
        }
    }
);
Example using JsonNode adapter of Content Manager

The following code calls the method getPageTitlesTree() of the JsonNode adapter without parameters:

cx.ajax(
         "block", // Equal to the return value of getName()
         "getBlocks", // Equal to the method name
         {
             data: {
                 // more parameters, which should be available for the method to use
             },
             success: function(json) {
                 // handle response
             }
         }
);

Using endpoint directly

Json adapters can be accessed using the following endpoint:

/api/Data/Json/<adapterName>/<method>[<params>]

Get data via PHP

JSON

Never call adapters directly, use JsonData everytime!

The following code calls the method getPageTitlesTree() of the JsonNode adapter without parameters:

$jsonData =  new \Cx\Core\Json\JsonData();
$pageTitlesTree = $jsonData->jsondata('node', 'getPageTitlesTree', array(), false);

Array for further processing

If the data have to be processed further, an associative array can be get instead of a JSON object:

$jsonData =  new \Cx\Core\Json\JsonData();
$pageTitlesTree = $jsonData->data('node', 'getPageTitlesTree');

After the processing the array can be converted to a json (use JsonData!).

$jsonData->json($pageTitlesTree);

From command-line

Json adapters can be accessed using the following command:

./cx Data Json <adapterName> <method>[ <params>]

Security

Contrexx 5 and newer

The security system of JsonData consists of the following three layers and are processed in the given order. The security system is based on objects of \Cx\Core\Access\Model\Entity\Permission. See API-Documentation of \Cx\Core\Access\Model\Entity\Permission about their functionality and possibilities.

1. Command-Layer

At first, the system verifies if the request is authorized to execute the requested command of the specified JsonAdapter. As the implementation of the Command-Layer is optional, the security system will move on to the next layer (Adapter-Layer) if it is missing. However, if the implementation has been done, the security system will decide on the Command-Layer-Implementation if the request is authorized. Further verification in the next layers will be skipped. The implementation is done by assigning an object of \Cx\Core\Access\Model\Entity\Permission to a given command in method getAccessableMethods() of the JsonAdapter. Example:

public function getAccessableMethods() {
    return array(
        // the command 'getData' has no security restrictions
        'getData',

        // the command 'setData' can only be accessed through protocol HTTPS and method POST
        // and the user who is performing the request must be signed in (3rd argument set to: true)
        'setData' => new \Cx\Core\Access\Model\Entity\Permission(array('https'), array('post'), true),
    );
}
2. Adapter-Layer

In case no Command-Layer has been implemented for the requested command, then the system will verify if the request is authorized to access the specified JsonAdapter. Again, the implementation of the Adapter-Layer is also optional and the security system will move on to the next layer (Application-Layer) if it is missing. However, if the implementation has been done, the security system will decide on the Adapter-Layer-Implementation if the request is authorized. Further verification in the next layer will be skipped. The implementation is done by returning an object of \Cx\Core\Access\Model\Entity\Permission in method getDefaultPermissions() of the JsonAdapter. Even though that the implementation of this layer is optional, the method getDefaultPermissions() still has to be defined in the JsonAdapter. However it is acceptable to just return null which indicated that the JsonAdapter does not implement a Adapter-Layer. Example:

public function getDefaultPermissions() {
    // the adapter can only be accessed through protocol HTTPS
    return new \Cx\Core\Access\Model\Entity\Permission(array('https'));
}
3. Application-Layer

At last, if neither the Command-Layer nor the Adapter-Layer has been implemented, then the system verifies if the request is authorized to use the JsonData-API at all. By default, the request is authorized if the user who is performing the request is authenticated. This can be changed by creating a Customizing of the method \Cx\Core\Json\JsonData::data() (core/Json/JsonData.class.php) and changing its default Permission-object which is defined by the following code:

$objPermission = new \Cx\Core\Access\Model\Entity\Permission(null, null, true, null);

Contrexx 3.x

This version of JsonData does not contain a security layer. JsonData does not handle permissions for the Frontend and neither for the Backend. Therefore, the adapters have to implement a security layer by themselves.