You are not logged in.

Dear visitor, welcome to WoltLab Bugtracker. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

  • Alexander Ebert

    WoltLab Developer

    You have to register first, to connect to this user.

32

Object actions in Community Framework 2.0

Rating:

by Alexander Ebert, Saturday, February 18th 2012, 3:44pm

This article is primarly intended for developers, describing some techniques behind a new feature of our upcoming version of Community Framework.

Another goal of Community Framework 2.0 was to create an abstract and more straight-forward system to execute recurring actions through a known interface. You might have already stumbled upon AbstractDatabaseObjectAction which is the default implementation for action processors and is usually expected by AJAXProxyAction. Basically it splits up into two different approaches, whereas we have the typical access from PHP on the one hand and the new AJAX calls on the other.

Each action class consists of three steps until an action may be successfully completed:
  1. __construct(): initialize the whole object and allow event listeners to modify all data before we’re actually working with it
  2. validateAction(): performs defined pre-execution against, e.g. validating permissions and parameters
  3. executeAction(): actually does the whole job by executing the action and providing the return values

If you remember the usual validation within those *Form-classes, you might wonder what’s the point behind validateAction(), why would you ever want to validate the same stuff two times? In fact you must and should not, because this method is primarily used (and actually forced) in AJAXProxyAction to ensure no action can be executed without a proper validation.

If you’re using PHP only, you might want to directly create the action object and execute it, skipping the validation. Even though it is possible it violates our general class design and is almost entirely unusable as you’re getting generic error messages in return.

The fancy AJAXProxyAction is nothing but a common wrapper which reads a specified list of parameters (and unserializes JSON automatically), executes validation before execution and returns the JSON-encoded response afterwards. I would say that in 95% of all cases you better stick with this one before creating an own action class for handling.

Let’s take a look at how this magic works, you might want to assume that you’re on AJAX and want to pass the action class “UserOptionAction”, invoking the method “create”. The AJAXProxyAction would invoke validateAction() which itself searches for a method called “validateCreate()” and executes it, errors are determined by throwing the adequate exception within the method, rather than working with boolean return values. Afterwards the method executeAction() is called which would invoke the method create() and returns the return values afterwards.

Most likely all your actions will succeed this way, but in some cases the action might fail due to different reasons. One reason might be that you call validateAction() but now matching validate*-method exists, in this case the whole requests fails with a permission denied error. If you ever forget to add a validate*-method, AJAX access will be automatically disabled for this method effectively protected by the framework itself. On the other hand you have to explicitly state those methods which may be called by guests, otherwise requests from guests will be automatically denied.

Three methods worth noticing are create(), delete() and update(), all of them are implemented by AbstractDatabaseObjectAction but feature an additional layer of security preventing illegal access. These 3 methods are not callable by guests (but you may enable it on your own) and each of them uses an own array called $permissions* (e.g. $permissionsCreate) which contents is checked against the user session permissions. The only way to disable these checks (in case your object does not have any permissions) would be overwriting the validateCreate() method or whichever of those magic three you’re using.

Below is the source code of PackageUpdateServerAction which shows a typical implementation of AbstractDatabaseObjectAction, please be aware that you may left out those $permissions*-arrays if you do not want to allow access on the 3 methods described above:

PHP Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
namespace wcf\data\package\update\server;
use wcf\data\AbstractDatabaseObjectAction;
use wcf\system\exception\ValidateActionException;
use wcf\system\WCF;

/**
 * (comment stripped)
 */
class PackageUpdateServerAction extends AbstractDatabaseObjectAction {
    /**
     * @see wcf\data\AbstractDatabaseObjectAction::$className
     */
    protected $className 'wcf\data\package\update\server\PackageUpdateServerEditor';

    /**
     * @see    wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
     */
    protected $permissionsCreate = array('admin.system.package.canEditServer');

    /**
     * @see    wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
     */
    protected $permissionsDelete = array('admin.system.package.canEditServer');

    /**
     * @see    wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
     */
    protected $permissionsUpdate = array('admin.system.package.canEditServer');

    /**
     * Validates permissions and parameters
     */
    public function validateToggle() {
        parent::validateUpdate();
    }

    /**
     * Toggles status.
     */
    public function toggle() {
        foreach ($this->objects as $server) {
            $server->update(array('disabled' => ($server->disabled) ? 1));
        }
    }
}

This article has been read 2,804 times.

Categories: Community Framework, Entwicklung


Blog navigation

Previous article

Decorator objects in Community Framework 2.0

by Alexander Ebert (Friday, February 17th 2012, 11:42pm)