Maslosoft Framework Logo Maslosoft Framework Documentation
Flexible Application Foundation


Controller Action Aspects

Basics

The action aspects allows execution of additional code for an action if it has aspect attached. Using aspects allows developing maintainable and reusable code that can be executed around controller actions. The aspect itself is a class implementing particular interface - nothing magic here. The interface names are self-explanatory and have only one method to implement.

The list of interfaces for controller actions in the execution order:

One aspect implementation can implement several interfaces, so that it can react on several points of execution.

Creating Action Aspect

To create new aspect for controller actions, implement one of forementioned interfaces.

For example let's create Aspect which will add extra CSS class to body for certain actions. We could as well add in action function body, or wrap it with some function and call it for each action. However it is not really related to action logic, but only adds extra processing to action. By using aspects, the extra processing is separated from action code literally.

class Wider implements BeforeRenderInterface
{
    const CssClass = 'wide-backend';

    public function beforeRender(Controller $controller = null, array $data = null)
    {
        Head::fly()->bodyCssClasses[] = self::CssClass;
    }
}

Using Action Aspect

To use aspect on action, add @Aspect annotation on desired action with parameter of class name of aspect. Class literal is recommended, allowing import and use of short name in annotation.

The extra @see doc tag is used to keep use statements by IDE's

class MyController extends Controller
{
    /**
     * @Aspect(Wider)
     * @see Wider
     */
    public function actionView()
    {
        // Action logic
        $this->render('my-view');
    }
}

In such setup the beforeRender method will be called after executing action logic, but before rendering output to the browser.

Using on all actions

Adding annotation on each action of controller would break DRY principle. Another option to apply aspect to all actions simply place same aspect on class declaration docblock.

/**
 * @Aspect(Wider)
 * @see Wider
 */
class MyController extends Controller
{
    public function actionView()
    {
        // Action logic
        $this->render('my-view');
    }
}

In setup like in the code snippet above, the Wider aspect will be applied for each controller action. This brings two benefits:

  • The code is not repeated
  • Each newly added action will have aspect too

The drawback is that currently it is not possible to remove aspect for selected actions. However this limitation can be mitigated by creating apposite aspect. For instance Narrower, which would revert the Wider aspect settings in our example.

The aspects for before/after action/render are evaluated by calling the type (class) aspect, then the particular action aspects are being applied.

Add @see doctag to instruct your IDE to keep use statements.

Built-in Controller Aspects

Class Name Documentation
DontReturn

The DontReturn aspect will instruct controller to not return to such action after authentication.

This can be used to prevent certain actions to redirect back after successful sign in, for instance when action serves image - this will prevent redirecting to image instead of page.

NoIndex

Use NoIndex aspect to instruct web crawlers to not index particular actions. This aspect will send no index headers, so that it is does not dependent on rendering.

Printing

Use printing aspect to instruct framework to switch rendering for printer friendly mode.

Use of this aspect implies WideBackend aspect.

TryToConvert
TryToImprove
WideBackend

Use this aspect to allow wider user interface. This aspect will enable container CSS class for content and add wide-backend CSS class for body HTML element.

The full behavior might be defined with CSS rules of active theme.