Sometimes you need additional information from the database for one of the components because you have created your own template for a subpart and it should display these information. If you only want to add information, extending existing component classes is troublesome. Another developer may want to add other information and several users might need the information from both classes in their templates.
A far better way is to create a HTML client decorator and to configure this decorator for the component where the information should be added to the views. In this case, anybody else can add both decorators (and more) to their components only by configuration. This way of stacking is far more flexible than extending classes.
The decorators you are implementing have to be stored in your own Aimeos extension in this directory:
The directory matches the namespace of the decorator class.
A basic skeleton for an HTML client decorator is simple as the abstract class contains all required logic to get a working decorator:
Decorators wrap around existing components like layers of an onion and there's no limitation in the numbers of layers. You only have to keep in mind that you will add another function call to the stack for each decorator you are adding.
Both, components and decorators must implement the same interface and therefore the same public methods. Thus, you can overwrite any public method but no private or protected ones. The list of public methods for both are:
The modifyBody() and modifyHeadder() methods are only used by components that implement content caching, like the catalog filter, list or detail component. Please have a look into the component you want to decorate if they support content caching an will call both methods.
Decorators inherit all methods also available in the components and subparts via the Aimeos\Client\Html\Base class and you can use them everywhere in your decorator. There's one additional method exclusive to decorators named getClient(). It returns the HTML client or decorator representing the next layer in the onion down to the core object:
public function process()
// do something before
// do something afterwards
You must use it to call the same method of the next object. Otherwise, the methods of the inner objects won't be executed.
Say you want to add the supplier object to the component because one of your new templates need to print some information about the supplier of the product. If this information should be available in both, body and header of the component, you should create a decorator like this:
public function addData( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
$view = parent::addData( $view, $tags, $expire );
// access already added data
$products = $view->get( 'listsItems',  );
// fetch some items from the database
$view->decoratornameMyparam = ...
For your parameters, you should use the name of your decorator as prefix to prevent overwriting parameters from other decorators or subparts.
After you've created your new decorator, you need to tell the factory to add it to the HTML client for the component. This is done via configuration, e.g. for the catalog detail component:
client/html/catalog/detail/decorators/global = array( 'Mydecorator' )
For the mini basket component, the configuration would be:
client/html/basket/mini/decorators/global = array( 'Mydecorator' )
You can add your decorator to every component you like as they all implement the same interface. In case you really want to add a decorator to ALL components, you can use this configuration setting instead:
client/html/common/decorators/default = array( 'Mydecorator' )
Remember that decorators suitable for all components must be very generic and must work not only for components creating the output for the browser but also for the components that are generating the e-mails executed by cronjobs on the command line!