Events
DGS can be managed and modified using events.
Listeners
You can subscribe to events in DGS using the listeners
tag or from PHP code.
listeners
tag
You can subscribe to events through XML:
<listeners>
<listener event="<?php echo Store::EVENT_BEFORE_INSERT; ?>"
plugin="Manager"
method="onCreateNewProduct" />
<listener event="<?php echo Store::EVENT_INSERT; ?>"
plugin="Manager"
method="onInsertNewProduct" />
</listeners>
Subscribing to Events from Code
/**
* @urlRule ~^/companies/new/$~
* @area admin
*/
public function onAjaxCreateForm(Response &$response): bool
{
$store = $this->createStoreInstance("company_create");
$method = array(&$this, 'onCreateNewCompany');
$store->addEventListener(Store::EVENT_BEFORE_INSERT, $method);
$store->onStart($response);
return true;
} // end onAjaxCreateForm
StoreActionEvent and FestiEvent Class
In the event handler method,
you can use the event classes FestiEvent
and StoreActionEvent
.
When using FestiEvent
, all data will be accessible through the method $event->getTarget()
or the attribute $event->target
.
It is recommended to use StoreActionEvent
, especially in systems with custom logic.
StoreActionEvent
allows for better compatibility with different core versions.
public function onSave(StoreActionEvent &$event)
{
$values = &$event->getValues();
// ...
}
Event Descriptions
Core::EVENT_ON_CREATE_STORE
This event is triggered every time a store is created in the system. It is useful for adding interceptors to view or modify all stores in the system.
Store::EVENT_BEFORE_INSERT
и Store::EVENT_BEFORE_UPDATE
This event is triggered before performing data updates. It is suitable for preparing additional fields, modifying data, or performing additional operations before updating data in the store.
The transaction is active at the time this event is executed.
Target:
id
- primary key valueinstance
- reference to theaction
values
- reference to the array of valuesaction
- name of theaction
response
- reference to the systemresponse
isUpdated
- flag indicating manual data update. If set to true, the system will not physically update the data and assumes that the event listener has performed the update.
$target = array(
'instance' => &$this,
'action' => $this->store->getAction(),
'id' => $this->primaryKeyValue,
'values' => &$values,
'data' => $this->data,
'isUpdated' => false
'response' => &$response
);
Store::EVENT_INSERT
и Store::EVENT_UPDATE
This event is triggered after adding or editing data. It is useful for updating additional data in the system.
The transaction is active at the time this event is executed.
Target:
id
- primary key valueinstance
- reference to theaction
values
- reference to the array of valuesaction
- name of theaction
response
- reference to the systemresponse
$target = array(
'instance' => &$this,
'action' => $this->store->getAction(),
'id' => $this->primaryKeyValue,
'values' => &$values,
'data' => $this->data,
'isUpdated' => false
'response' => &$response
);
Store::EVENT_UPDATE_VALUES
Occurs after adding/editing data.
This event is triggered immediately after the Store::EVENT_INSERT
or Store::EVENT_UPDATE
events.
Target:
id
- primary key valueinstance
- reference to theaction
values
- reference to the array of valuesaction
- name of theaction
response
- reference to the systemresponse
$target = array(
'instance' => &$this,
'action' => $this->store->getAction(),
'id' => $this->primaryKeyValue,
'values' => &$values,
'data' => $this->data,
'isUpdated' => false
'response' => &$response
);
Store::EVENT_PREPARE_ACTION_REQUEST
Event for preparing request data. Called before Store::EVENT_PREPARE_VALUES
.
Convenient to use for adding custom data to prepare values.
Target:
instance
- reference to theaction
request
- reference to the array with request dataaction
- name of theaction
$target = array(
'instance' => &$this,
'request' => &$request,
'action' => $this->store->getAction()
);
Store::EVENT_PREPARE_VALUES
Event that is called after processing request data and before updating data in the storage.
Target:
instance
- reference to theaction
values
- reference to the array of valuesaction
- name of theaction
$target = array(
'instance' => &$this,
'values' => &$result,
'action' => $this->store->getAction()
);
Store::EVENT_ON_FETCH_LIST
Event for preparing content of the data list. Can be used to add content to the list.
<listeners>
<listener event="<?php echo Store::EVENT_ON_FETCH_LIST; ?>"
plugin="Deals"
method="onFetchListContent" />
</listeners>
public function onFetchListContent(FestiEvent &$event)
{
$event->target['content'] .= $this->fetch('form_create_deal.phtml');
}
Store::EVENT_ON_LIST_GENERAL_ACTIONS
Event for preparing general action list for the list. Displayed above the list.
Store::EVENT_ON_LOAD_LIST_DATA
Event for preparing data for displaying the data list.
Target:
info
- reference to the table formation optionsdata
- reference to the array with data used for displaytableData
- reference to the datafilters
- filtersstore
- reference to thestore
Store::EVENT_ON_FIELDS_PREFILL_VALUES
Called when preparing default values for adding a new record.
Target
instance
- reference to theaction
action
- name of theaction
fields
- reference on list of thestore
fieldsvalues
- reference to the values arraystore
- reference to thestore
$storage->addEventListener(
Store::EVENT_ON_FIELDS_PREFILL_VALUES,
array(&$this, 'onPrepareFormFields')
);
...
public function onPrepareFormFields(\StoreActionEvent &$event): void
{
}
Store::EVENT_ON_FETCH_LIST_CELL_VALUE_WITH_LINK
This event is triggered when preparing a link in the list of records and cells.
Target
url
- linkvalue
- cell valuefield
- reference to thefield
primaryKeyValue
- primary key value for the rowrow
- array of row valuestarget
- link's target attribute(default_self
)
$storage->addEventListener(
Store::EVENT_ON_FETCH_LIST_CELL_VALUE_WITH_LINK,
array(&$this, 'onPrepareListCellValueLink')
);
Store::EVENT_AFTER_UPDATE
This event is triggered after adding/editing data and after the data is saved. It is used to implement After Commit logic, such as making requests to a remote API that cannot be executed within a transaction.
This event should be used only in rare cases.
Store::EVENT_ON_REMOVE_INTEGRITY
When deleting data, there are often cases where we cannot delete it directly as it would violate data integrity.
Usually, such data has additional deletion logic or requires a status change.
For such cases, the Store::EVENT_ON_REMOVE_INTEGRITY
event should be used:
<listeners>
<listener event="<?php echo Store::EVENT_ON_REMOVE_INTEGRITY; ?>"
plugin="Companies"
method="onRemoveUserWithIntegrityError" />
</listeners>
public function onRemoveUserWithIntegrityError(StoreActionEvent &$event)
{
$idUser = (int) $event->getPrimaryKeyValue();
$values = array(
'status' => UserValuesObject::STATUS_DELETED
);
$this->object->changeUser($values, $idUser);
$event->setUpdated();
return true;
}
Store::EVENT_ON_LIST_ACTIONS
Sometimes, you may need to have different actions on different rows depending on the data in the record.
Let's consider an example where the delete button should not be displayed on rows where the status
is set to created
:
-
Subscribe to the
Store::EVENT_ON_LIST_ACTIONS
event. -
Write the handler:
public function onListActions(FestiEvent &$event) { $status = $event->target['values']['status']; if ($status != "created") { return false; } $actions = &$event->target['actions']; $index = array_search(Store::ACTION_REMOVE, $actions); unset($actions[$index]); return true; }
This event is triggered when displaying a value for a field filter.
Target
instance
- reference to thefield
field
- name of thefield
action
- name of theaction
value
- filter valuevalues
- filter value forForeignKey
,Many2many
, andDatetime
fields
Store::EVENT_ON_FETCH_FIELD_FILTER
| core\store\event\IPrepareListItem
This event is triggered before data is formatted for a cell in ListAction
.
Event class: core\store\event\ListItemEvent
Example usage of the event to modify data for display in a cell.
Store::EVENT_PREPARE_REPOSITORY_VALUES
This event is triggered when preparing values for updating data in the database.
Target
general
- reference to values for tablescallback
- reference to values for tables with dynamic logicstore
- reference to theStore
$store->addEventListener(Store::EVENT_PREPARE_REPOSITORY_VALUES, function (FestiEvent &$event) {
$tablesValues = &$event->getTargetValueByKey('general');
$store = $event->getTargetValueByKey('store');
assert($store instanceof Store);
if ($store->getAction() == Store::ACTION_INSERT) {
$tablesValues['employees']['cdate'] = date('Y-m-d');
} else {
$tablesValues['employees']['mdate'] = date('Y-m-d H:i:s');
}
});
Example of DGS when additional columns need to be added, not retrieved from the database, but populated from a plugin:
<?xml version="1.0" encoding="UTF-8" ?>
<table charset="UTF-8"
name="cloud_services"
primaryKey="id"
defaultOrderField="id"
defaultOrderDirection="ASC"
rowsForPage="20"
emptyMessage="<?php echo __('Not found Services...')?>">
<fields>
<field type="text"
name="caption"
caption="<?php echo __('Service'); ?>"
width="30%" />
<field type="text"
caption="<?php echo __('Host'); ?>"
name="host"
width="30%"
isCustom="true" />
<field type="text"
caption="<?php echo __('Status'); ?>"
name="status"
width="30%"
isCustom="true" />
</fields>
<listeners>
<listener event="<?php echo Store::EVENT_ON_LOAD_LIST_DATA; ?>"
plugin="FestiCloudServicesManager"
method="onLoadListData" />
</listeners>
<actions>
<action type="list" caption="<?php echo __('Services'); ?>" />
<action type="toggle"
caption="<?php echo __l('Enable'); ?>"
confirmDialog="true"
dialogTitle="<?php echo __('Confirmation'); ?>"
dialogMessage="<?php echo __('Are you sure?'); ?>"
link="<?php echo Core::getInstance()->getUrl('/app/%s/services/%%id%%/toggle/', App::getID()); ?>" />
</actions>
</table>
public function onLoadListData(FestiEvent &$event)
{
$tableData = &$event->target['data'];
$indexes = &$event->target['info']['indexes'];
$idApp = App::getID();
$statusIndex = $indexes['status'];
$hostIndex = $indexes['host'];
$services = $this->_loadServicesByAppID($idApp);
foreach ($tableData as &$row) {
$this->_prepareServiceRow(
$row,
$services,
$statusIndex,
$hostIndex
);
}
} // end onLoadListData
private function _prepareServiceRow(
&$row, $services, $statusIndex, $hostIndex
)
{
$idService = $row['id'];
$status = &$row['data'][$statusIndex]['value'];
$host = &$row['data'][$hostIndex]['value'];
if (empty($services[$idService])) {
$status = '—';
$host = '—';
} else {
$service = $services[$idService];
$status = $service['status'];
$host = $service['host'].":".$service['port'];
}
return true;
} // end _prepareServiceRow
Store::EVENT_ON_LOAD_ACTION_ROWS
When it is necessary to modify a value for display in a list or populate values for custom fields:
$store = $this->createStoreInstance('report_offer_acceptance_rate');
$store->addEventListener(Store::EVENT_ON_LOAD_ACTION_ROWS, function (FestiEvent &$event) {
$rows = &$event->getTargetValueByKey('values');
foreach ($rows as &$row) {
$row['rate'] = $row['offer_cnt'] ? ($row['completed_cnt'] * 100) / $row['offer_cnt'] : 0;
$row['rate'] = number_format($row['rate'], 2).'%';
}
});
Store::EVENT_ON_LOAD_CHILD_FIELD_VALUES
This event is triggered when it is necessary to load child field values based on a parent field value. It is typically used in scenarios where a field's options depend on the selection of another field, such as in cascading dropdowns.
AbstractAction Event
AbstractAction::EVENT_PREPARE_FOREIGN_FIELD_VALUES
This event is triggered when preparing values for a foreign field.
Target
ajaxChild
- child field nameajaxChildValues
- values of theajaxChild
ajaxParent
- parent field namefieldName
- current field nameterm
- search stringvalue
- current field valueexclude
- excluded fieldsresults
- array of items for the field
Usage
- Subscribe to the Event: To use this event, you need to subscribe to it in your store class.
$store->addEventListener(Store::EVENT_ON_LOAD_CHILD_FIELD_VALUES, function (FestiEvent &$event) {
// Your event handling logic here
});
- Event Handler: Implement the event handler to process the event. The handler can modify the target values or perform additional logic.
public function onLoadChildValuesHandler(FestiEvent &$event)
{
// Access the target values
$parentField = &$event->getTargetValueByKey('parentField');
$childField = &$event->getTargetValueByKey('childField');
$options = &$event->getTargetValueByKey('options');
$values = &$event->getValues();
// Custom logic to load child field values
$values = $this->loadCustomChildValues($parentField, $childField, $options);
}
This example demonstrates how to handle the event to load child field values based on the parent field's value.
ListItemEvent::EVENT_ON_PREPARE_LIST_ITEM
Override DGS
class ModuleOptionsStore extends Store implements IBeforeInsertListener
{
public function onBeforeInsertHandler(StoreActionEvent &$event): void
{
$rows = $event->getValues();
foreach ($rows as $key => $value) {
$values = array(
'value' => $value
);
$search = array(
'name' => $key
);
$this->_object->change($values, $search);
}
$event->setUpdated(true);
}
}
Creating a New Event in DGS
- Create a class for the event of a specific entity (if it doesn't already exist):
namespace core\store\event; class ListItemEvent extends \FestiEvent { }
- Add a constant with the event name to the event class:
php class ListItemEvent extends \FestiEvent { public const EVENT_ON_PREPARE_LIST_ITEM = "on_prepare_list_item"; }
- Initialize the event class:
$target = array( 'field' => &$field, 'row' => &$row, 'value' => &$value ); $event = new ListItemEvent(ListItemEvent::EVENT_ON_PREPARE_LIST_ITEM);
-
Create an interface for the event listener (its name should be similar to the event constant). It's recommended to prefix the method name with
on
and postfix it withHandler
. The method can accept either the event class or you can pass the necessary parameters directly to the method:
5. Trigger the event in DGS:namespace core\store\event; interface IPrepareListItem { public function onPrepareListItemHandler(IStoreField &$field, mixed &$value, array &$row): void; }
6. Add documentation for the event.$this->store->dispatchEvent($event); if ($this->store instanceof IPrepareListItem) { $this->store->onPrepareListItemHandler($field, $value, $row); }