Maslosoft Framework Logo Maslosoft Framework Documentation
Flexible Application Foundation


Widget Actions A.K.A. Microcontroller Architecture

This is so-called microcontroller architecture, allowing to call widget method by especially crafted URL. So that widget act like controller with actions.

Use cases include, but are not limited to:

  • Sorting data
  • Searching
  • Pagination
  • Storing persitent state

Depending on situation, action will be called on client side widget instance or on server side.

Creating Server Side Microcontroller Widget

Evaluating Actions

To make actions available in widget, it need to have initialized actions evaluator (Actions). It will intercept request and call apropriate methods if applicable. This should be placed in widget's init method. Actions takes two arguments, first the widget isntance itself and the boolean value indicating whether should call action now, or manually later.

Example:

Instant calling of action, this code will execute any method that is passed by request.

private $actions = null;

public function init()
{
    $this->actions = new Actions($this);
}

Example of delayed calling:

Delayed calling might be usefull if some other tasks need to be done before evaluating actions.

private $actions = null;

public function init()
{
    $this->actions = new Actions($this, false);
}

public function run()
{
    $this->actions->call();
}

Widget Action Method

To create widget action, there first of all, the widget itself need to have public method starting with action prefix, for example actionSearch. This method will be called when URL containing widget ID will arrive to widget instance. Additional parameters can be passed to widget action method.

This prefix is required to prevent calling arbitrary widget methods from JavaScript

Parameters

Parameters passed to widget, are - depending on their URL value - either string or hashed array.

Note that widget method should check if parameters are valid and react accordingly.

Auto-bound parameters

Widget can have many parameters passed by calling URL with widget ID, action name and parameters. Note that if expected values might contain colon :, raw parameters can be used.

Example URL could be ?m18DDYa.page=num:2 which will result in int value of 2 bound to method argument named num.

Example action method could be like following:

public function actionPage($num)
{
    $page = $num;
    ...
}
Array parameters

URL containing widget ID, method name and value separated by colon :, for example URL m1YmTZj.sort=fullName:desc will call method actionSort of widget with ID m1YmTZj with array parameters if the method have one variadic parameter list, denoted by ....

[
    'fullName' => 'desc'
]

The method signature to match such params could be for example:

public function actionSort(...$sort)
{
    ...
}
Raw parameters

In some cases, it is desirable to obtain raw data from passed parameters, for instance search query string. This can be retrieved by calling widget actions evaluator instance (Actions) with action name:

$params = $this->action->get('search')->rawArguments;

For example URL of ?top-search.search=user this will return string user, regardless of how it is formatted.

In case of raw arguments, action method itself does not even need a parameter:

public function actionSearch()
{
    $params = $this->getActions()->get('search')->rawArguments;
}

Creating client side widget

Client side of widget should have class name same as server side one. It can be initalized in widget's init method. It should be located in js sub folder of current widget.

PHP widget inializing JS part

JavaScript part of widget have id as a parameter:

class MyWidget
{
    public function init()
    {
        new JsWidget($this, [JavaScript::encode($this->id)]);
    }
}

JavaScript side widget

This example is written in CoffeeScript. In this example, dispatcher is used smilarly to PHP's widget dispatcher Actions. This allows both executing actions on URL change, as well as calling remote action.

See also activities for more informations on dispatcher.

Dispatcher takes up to three parameters:

  • Widget instance
  • Instance of object holding actions
  • Instance of object holding activities

The JavaScript widgets do not use action prefix, as any action can be called by client anyway. In this scenario, calling virtual URL m1YmTZj.sort=fullName:desc matching @id passed in constructor, will call sort method.

class MyWidget

    constructor: (@id) ->
        @dispatcher = new Maslosoft.Widgets.Dispatcher @, @

    sort: (columns, e) =>
        # Call this widget's server side method
        @dispatcher.remote 'sort', columns
Complex parameters

The dispatcher's remote action can send arbitrary data to server, which will be decoded like if it was JSON data. The topmost named arguments will be auto wired to PHP function argument names.

class MyWidget

    constructor: (@id) ->
        @dispatcher = new Maslosoft.Widgets.Dispatcher @, @

    sort: () =>
        data = {
            direction: 1,
            field: 'name',
            parentIds: [1, 2, 3],
            filter: {published: true}
        }
        @dispatcher.remote 'sort', data

On the server side, the widget method actionSort, when having proper signature will receive JavaScript parameters as PHP values:

class MyWidget
{
    ...
    public function actionSort($direction, $field, $parentIds, $filter)
    {
        var_dump($direction);   // Integer `1`
        var_dump($field);       // String `name`
        var_dump($parentIds);   // Integer array `[1,2,3]`
        var_dump($filter);      // stdClass object with property `published` having value `true`
    }
    ...
}

Creating URL's and links

URL's in this example might look convoluted in some cases, especially for generated widget ID's, like m18DDYa. But no worries here, these URL's are created by specialized classes of ActionUrl and ActionLinkfor creating whole link tag.

Creating URL

To create URL, echo ActionUrl with apropriate parameters, for example to sort with name desc, let's assume widget ID users:

echo new ActionUrl($widget, 'sort', ['name' => 'dest']);

Will result in URL:

?user.sort=name:desc

Creating link

The class ActionLink will create whole tag, with rel="virtual" attribute, so that it will call javascript widget method, which can call server method via AJAX.

echo new ActionLink($widget, 'sort', 'Sort by name', ['name' => 'dest']);

Will result in link:

<a href="?user.sort=name:desc" rel="virtual">Sort by name</a>