Skip to main content

Item field plugin events

Create this plugin

The pages of this guide:

In every card, "the field" is the field as staff defined it, with these properties among others: id, type, field_name, display_name, informational, params_decoded and values (the values of the pool, each with id, display_name and params_decoded).

onItemView​

When it fires. When Alfa prepares an item page, once for each field of the item. Also when staff open the popup that configures an item for an order in the administrator.

Who receives it. One plugin (targeted): the plugin of the field's type.

What you are given. An ItemViewEvent (Alfa\Component\Alfa\Administrator\Event\ItemFields\ItemViewEvent).

GetterWhat it returns
getItem()The item. Among its properties: variant (what the shopper's picks led to, see the sample), options (the values the item offers as extras), selectedOptionValueIds, informational.
getField(): objectThe field
getConfig(): RegistryThe settings your plugin stored for this field on this item. Empty when none.
getCurrentValue()The composition already stored for this field, when the shopper or staff edit an existing line. null otherwise.
getSelections(): arrayWhat is chosen across all fields now: ['sel' => [field id => value id], 'opt' => [value ids]]
getSelectedValueIds(): int[]The same, as one flat list of value ids

What you are expected to do. Pick the place of the page, name a layout, pass its data:

$event->buyForm()
->setLayout('item-radio')
->variantSelector($fieldId)
->setData(['field' => $field, 'values' => $field->values]);

The places of the item page, each returning a builder:

MethodPlace
buyForm()Inside the buy form. This is where a control the shopper answers goes.
specifications()The read only specifications block
title(), image()Beside the title, on the image
shortDescription(), fullDescription()In the description blocks
nearAddToCart()Next to the add to cart button

The builder's methods:

MethodMeaning
setLayout(string $layout)The layout file's name, without .php
setData(array|object $data)The data the layout receives
variantSelector(int $fieldId)"This place holds the control of a variant field." Alfa adds inputName (sel[<field id>]) and reloadScope (item) to the layout's data. A change reloads the whole item.
optionSelector(int $fieldId)"This place holds the control of an option." Alfa adds inputName (opt[<field id>]) and reloadScope (price). A change only prices again.
setPluginType(), setPluginName()Rarely needed: render another plugin's layout

Your layout must give its input the name in $inputName and the attribute data-item-reload with $reloadScope. Declare variantSelector() only for a field that is a dimension of the item's combinations, and optionSelector() only for one that is not.

You may also replace the add to cart area of the page with setCartLayout(string $layout) and setCartLayoutData(array|object $data), or add a block beside it with setCartChildLayout() and setCartChildLayoutData(). When several fields replace the area, the last one wins.

What happens next. Alfa collects the places of every field in order, and the item template renders them. A field condition set on the item field is applied around your layout by Alfa.

If you are missing or you fail.

What is wrongWhat Alfa does
The plugin is disabled, missing or cannot be loadedThe field is not drawn. The page shows without it.
The selector kind does not match the field's useOn a site in debug mode, an error. Otherwise a warning in Joomla's log, category alfa-item-fields.
The layout file does not existYour layout is not drawn. Alfa falls back to a default layout of its own or to nothing. In debug mode a warning names the missing file.
Your method throws an errorAlfa does not catch it at this point. Do not let an error leave onItemView.

onItemListPrepare​

When it fires. When Alfa builds a card of an item list, once for each field of the item that has "Show on listings" on. A card can be built twice in one request, so act only through the event.

Who receives it. One plugin (targeted): the plugin of the field's type.

What you are given. An ItemListPrepareEvent.

GetterWhat it returns
getItem(): objectThe item of the card
getField(): objectThe field

What you are expected to do. The same as on the item page, with the places a card has: buyForm(), specifications(), title() and image(). The builder and the cart area methods are the same.

What happens next. The card renders your layout. If a field the shopper must answer drew no control on the card, Alfa turns the card's button into a "Choose options" link to the item page. A cart area your plugin set is never replaced by that link.

If you are missing or you fail. A missing plugin draws nothing, and the same log line is written for it. An error you throw is written to Joomla's log (category com_alfa) with the field's type, and the card keeps its normal add to cart area.

onItemsListPrepare​

When it fires. Once per item list, after every card is fully built. Also after a single card is reloaded.

Who receives it. Everyone (broadcast). The base class already subscribes your plugin. It arrives whether or not the list contains a field of your type.

What you are given. An ItemsListPrepareEvent with one getter, getItems(): array, the items of the page.

What you are expected to do. Change the items directly when you need something across cards. The event has no setters.

What happens next. The list is rendered with the items as you left them.

If you are missing or you fail. An error you throw is written to Joomla's log (category com_alfa.plugins). The other listeners still run and the list is shown.

onItemFieldValueFacetGroups​

When it fires. When Alfa builds the filters of an item list, once for each field, never once per value.

Who receives it. One plugin (targeted), and only when your class has this method.

What you are given. A ValueFacetGroupsEvent.

GetterWhat it returns
getField(): objectThe field
getValues(): arrayThe field's values, keyed by value id. Each is an array with at least id, name and params.

What you are expected to do. Say which groups a value belongs to, when several values should be offered as one filter entry. The shipped choice plugin uses it to offer "Blue", "Navy Blue" and "Blue and Red" under one colour.

MethodMeaning
putValueGroups(int $valueId, array $groups)The groups of one value. Each group is an array: type and id (yours to choose, Alfa only compares them), label, and optionally layout, layoutData and ordering. A value can be in several groups.
putValueLayout(int $valueId, string $layout, array $data = [])How one value draws itself when it is listed alone
putFieldGrouping(bool $grouping)Whether this field wants its values grouped

What happens next. Alfa builds the filter entries, the counts and the query from your answer. You never write SQL or HTML for a filter.

If you are missing or you fail. Each value is offered alone. An error you throw is written to Joomla's log (category com_alfa) and has the same result.

onValidateCartAdd​

When it fires. When an item is added to the cart, and when staff save an order line, after Alfa's own checks: a combination is chosen, and every required field has an answer. Once for each field of the item.

Who receives it. One plugin (targeted).

What you are given. A ValidateCartAddEvent.

GetterWhat it returns
getItem(): object, getField(): objectThe item and the field
getPayload(): stringThe composition sent for this field, as text, exactly as the browser sent it. Never trust it. Empty when none.
getConfig(): RegistryThe settings of this field on this item
getQuantity(): floatThe quantity asked for
getSelections(), getSelectedValueIds()What is chosen across all fields

What you are expected to do. If the choice is not acceptable, call setError(string $message) with a translated sentence for the shopper. Otherwise do nothing.

What happens next. With an error, the item is not added and the shopper sees your sentence. Without one, Alfa goes on.

If you are missing or you fail. A missing plugin takes no part, except for a required field: an item with a required field whose plugin is unavailable cannot be added, and the shopper is told. An error you throw is written to Joomla's log (category com_alfa.cart), the item is not added, and the shopper sees a general "invalid selection" message.

note

ValidateCartAddEvent also has setSnapshot() and setPriceImpact(). In 2.2.0 nothing reads what they set. Store data with onPrepareForCart and change the price with onCalculateItemPrice.

onPrepareForCart​

When it fires. After the checks above and before the cart line or the order line is written, for a field that takes a composition and was sent one.

Who receives it. One plugin (targeted), and only when your class has this method. Having the method is also how your plugin says that its fields take a composition at all. A composition sent for a field whose plugin has no such method is refused before anything is stored.

What you are given. A PrepareForCartEvent.

GetterWhat it returns
getItem(): object, getField(): objectThe item and the field
getPayload(): stringThe full composition as the browser sent it. Never trust it.
getFiles(): arrayThe files uploaded for this field: slot to one file array (name, type, tmp_name, error, size)
getConfig(): RegistryThe settings of this field on this item
getSelections(), getSelectedValueIds()What is chosen across all fields

What you are expected to do. Check the composition, move uploaded files to where you keep them, and call setStoredPayload(array|string $payload) with what should be stored. An array is stored as JSON. To refuse, call setError(string $message).

What happens next. Alfa stores your answer on the cart line (#__alfa_cart_item_fields.payload). It comes back to you as getPayload() in onCalculateItemPrice, as getSnapshot() in onCartItemView and as getCurrentValue() in onItemView. If you set nothing, the composition is stored as sent.

If you are missing or you fail. With setError(), the line is not written and the shopper sees your sentence. An error you throw is written to Joomla's log (category com_alfa.cart) and the shopper sees a general "invalid selection" message.

On the storefront the browser sends a composition as conf[<field id>].

onCalculateItemPrice​

When it fires. Each time Alfa works out the price of an item for which at least one composition exists: on the item page while the shopper builds one, and for a cart line that carries one. It then fires once for each field of the item, also for the fields without a composition. It does not fire when there is no composition at all, which is the case for the cards of an item list.

Who receives it. One plugin (targeted).

What you are given. A CalculateItemPriceEvent.

GetterWhat it returns
getItem(): object, getField(): objectThe item and the field
getPayload(): mixedThe composition for this field. null when this field has none.
getConfig(): RegistryThe settings of this field on this item
getContext(): ?objectThe pricing context (currency, place, customer group, quantity), when there is one
getSelections(), getSelectedValueIds()What is chosen across all fields

What you are expected to do. Add price lines. A line says what to do, not what the result is:

$event->contribution('engraving.text')
->label('Engraving')
->add(5.00)
->onGross();
Method of the lineMeaning
label(string $label)The text shown in the price breakdown. Required.
add(float $amount), subtract(float $amount)Add or take off an amount of money
percent(float $percent), subtractPercent(float $percent)Add or take off a percentage
onNet(), onGross()Apply to the price before tax, or to the price with tax
sortOrder(int $sortOrder)Lines with a lower number are applied first

The first argument of contribution() is a code of your own that identifies the line. Work the amount out on the server from getConfig() and the composition. Never take an amount from the browser.

What happens next. Alfa applies the lines of all fields in order, and each appears as a step of the price breakdown.

If you are missing or you fail. An error you throw is written to Joomla's log (category com_alfa.pricing) and the price is worked out without your lines. On a site in debug mode the error is shown instead. When the plugin is unavailable, see "When the plugin is unavailable" below.

note

CalculateItemPriceEvent also has setOverrideFinal(). In 2.2.0 nothing reads what it sets.

onCartItemView​

When it fires. When Alfa prepares a cart line for display, once for each field choice the line carries.

Who receives it. One plugin (targeted).

What you are given. A CartItemViewEvent.

GetterWhat it returns
getLine()The cart line
getField(): objectThe field
getSnapshot(): arrayThe composition stored for this field on this line. Empty when none.
getConfig(): RegistryThe settings of this field on this item

What you are expected to do. Only if you want your own look: $event->main()->setLayout(...)->setData(...). main() is the one place a cart line has.

What happens next. If you set no layout, Alfa draws the field as "label: value" itself.

If you are missing or you fail. A missing plugin gets the standard "label: value". Alfa does not catch an error you throw at this point. Do not let an error leave onCartItemView.

onGetFieldActions​

When it fires. When the administrator draws a row that your field belongs to: a combination or an option on the item's edit screen.

Who receives it. One plugin (targeted).

What you are given. A GetFieldActionsEvent.

GetterWhat it returns
getScope(): stringWhich kind of row: item, combination, option or order
getScopeId(): intThe row's id
getItemId(): intThe item
getField(): objectThe field

What you are expected to do. Offer buttons:

$event->add('configure', 'Configure')->icon('cog')->readOnly();

add(string $id, string $label) returns the button. Its methods include icon(), css(), confirm(), tooltip(), priority(), disabled(), readOnly() and mutating(). A button changes data unless you mark it readOnly(). A button that only opens a popup is read only.

What happens next. Alfa draws the buttons on the row. A click runs onExecuteFieldAction.

If you are missing or you fail. No buttons, and staff see a warning on the screen. An error you throw is shown to staff the same way.

onExecuteFieldAction​

When it fires. When staff click one of your buttons, or a button inside your popup.

Who receives it. One plugin (targeted). Staff need the permission to edit items, and for an order row the permission to edit orders.

What you are given. An ExecuteFieldActionEvent.

GetterWhat it returns
getAction(): stringThe id of the action
getScope(), getScopeId(), getItemId(), getField()The row, as in onGetFieldActions
getData(): arrayWhat the browser sent with the click, for example the values of your popup's form

What you are expected to do. Produce an outcome on the event:

MethodOutcome
setLayout(string $layout), setLayoutData(array $data)Show one of your layouts in a popup
setModalTitle(string $title)The popup's title
addButton(string $label, array $opts = [])A footer button of the popup. Without options it closes. ['reload' => true] closes and reloads. ['action' => 'id'] runs another of your actions in the same popup.
setMessage(string $message)Report a result
setError(string $message)Report a failure
setRefresh(bool $refresh)Reload the screen afterwards
setRedirectUrl(string $url)Send staff to another page
setPayload(array $payload)Data for your own script

Read and write the row's settings with $this->getConfig($event) and $this->saveConfig($event, $config).

What happens next. Alfa shows your outcome. An action that changes data runs only from a POST request, and on the action page only with a one time key, so a reloaded page cannot run it twice.

If you are missing or you fail. Staff see an error saying that the plugin is not available. An error you throw is shown to staff as the action's failure.

onClearData​

When it fires. When staff use Clear Data or "Remove extension and its data" for your plugin under Tools: Extensions, or "Clear everything".

Who receives it. One plugin (targeted), and only when your class has this method. Alfa may call it while the plugin is disabled.

What you are given. A ClearDataEvent (Alfa\Component\Alfa\Administrator\Event\Tools\ClearDataEvent) with getSource(): string, which says which of the three actions asked.

What you are expected to do. Remove the data your plugin owns outside Alfa's tables, for example uploaded files. Then call setMessage(string $message) with one line about what was removed. If something could not be removed, call setError(string $error).

What happens next. Staff see your message or your error.

If you are missing or you fail. Without the method, staff are told that automatic Clear Data is not supported and nothing is touched. An error you throw is logged and reported as a failure.