# Définition des données
Il faut définir la liste des métriques que l'on souhaite représenter ainsi que la méthode pour les évaluer, et ce, pour chaque Smart Structure que l'on souhaite étudier.
À chaque Smart Element de cette Smart Structure correspondra une entrée dans la base de donnée dédiée au module Dashboard, cette entrée se composera l'ensemble des métriques évaluées sur le Smart Element.
# Définir la liste des métriques
La configuration de la liste des métriques d'une Smart Structure donnée est réalisée avec un fichier XML. Ce fichier
doit utiliser le namespace
https://platform.anakeen.com/4/schemas/dashboard-table/1.0
.
Il permet de définir la structure de la table qui sera créée dans la base de données.
Les propriétés à référencer sont :
- le nom de la table
- la liste des métriques
<dashboard:field />
# Modèle
src/vendor/<vendorName>/<moduleName>/SmartStructures/<structureName>/<structureName>Dashboard.xml
<?xml version="1.0" encoding="UTF-8"?>
<dashboard:table name="<tableName>" xmlns:dashboard="https://platform.anakeen.com/4/schemas/dashboard-table/1.0">
<dashboard:field type='<type1>' name='<prop1>' />
<dashboard:field type='<type2>' name='<prop2>' nullable='true' />
...
</dashboard:table>
# Options
Chaque indicateur peut être marqué comme nullable
. Le cas échéant la valeur de l'indicateur pourra ne pas être
renseignée lors de l'évaluation.
Informations
Cela est nécessaire pour toutes les métriques qui peuvent être indéfinies. Par exemple, si une métrique dépend d'une
étape spécifique du cycle de vie, elle peut alors être évaluée à null
si le Smart Element est à une étape différente.
# Types disponibles
Type | Description | Options |
---|---|---|
smallint | entier sur 2 octets | |
integer | entier | |
decimal | nombre décimal | precision , scale |
float | nombre flottant | |
string | chaîne de caractères avec longueur maximale | length |
ascii_string | chaîne de caractères ascii avec longueur maximale | |
text | chaîne de caractères sans longueur maximale | |
guid | GUID | |
boolean | booléen | |
date | date sans timezone | |
datetime | date et heure sans timezone | |
datetimetz | date et heure avec timezone | |
array | tableau | |
simple_array | tableau scalaire | |
json | json | |
object | objet |
Informations
Ce sont les types supportés par Doctrine, l'ORM sous-jacent utilisé par l'ETL. Plus d'informations sur ces types ici.
# Exemple
Exemple issu du How To :
<?xml version="1.0" encoding="UTF-8"?>
<dashboard:table name="menu" xmlns:dashboard="https://platform.anakeen.com/4/schemas/dashboard-table/1.0">
<dashboard:field type='float' name='price' />
<dashboard:field type='float' name='discount' nullable='true' />
<dashboard:field type='integer' name='nb_plats' />
<dashboard:field type='date' name='creation' />
</dashboard:table>
# Définir le calcul des métriques
La définition seule des métriques n'est pas suffisante, il faut également définir :
- quelles Smart Structures traiter
- comment calculer les métriques pour chacune d'entre elles
Pour indiquer que l'on souhaite traiter une Smart Structure, il suffit d'étendre sa classe
<smartStructure>Behavior.php
en implémentant l'interface IDashboardElement
.
# Interface IDashboardElement
<?php
namespace Anakeen\Dashboard;
interface IDashboardElement
{
public static function getConfigurationFile(): string;
public function aggregateData(ADashboardEntity &$entity);
}
getConfigurationFile()
doit retourner le chemin vers le fichier de configuration de la liste des métriques<smartStructure>Dashboard.xml
aggregateData()
doit évaluer les métriques sur le Smart Element courant
# Modèle
<?php
namespace <vendorName>\<moduleName>\SmartStructures\<structureName>;
use Anakeen\Dashboard\ADashboardEntity;
use Anakeen\Dashboard\IDashboardElement;
class <smartStructure>Behavior extends \Anakeen\SmartElement implements IDashboardElement
{
public static function getConfigurationFile(): string
{
return __DIR__ . '/<smartStructure>Dashboard.xml';
}
public function aggregateData(ADashboardEntity|DashboardEntity &$entity)
{
$entity->prop1 = ...;
$entity->prop2 = ...;
...
}
}
où DashboardEntity
est une classe php générée à partir du fichier de configuration.
Cette classe a pour namespace
<vendorName>\<moduleName>\SmartStructures\<structureName>
et hérite de la classeADashboardEntity
. Elle possède comme attributs l'ensemble des métriques listées.
# Exemple
Exemple issu du How To :
<?php
namespace Cogip\Restauratec\SmartStructures\Menu;
use Anakeen\Dashboard\IDashboardElement;
use Anakeen\Dashboard\ADashboardEntity;
use SmartStructure\Fields\Consommable as ConsommableFields;
use SmartStructure\Fields\Menu as MenuFields;
use Anakeen\Core\SEManager;
class MenuBehavior extends \Anakeen\SmartElement implements IDashboardElement
{
public function registerHooks()
{
parent::registerHooks();
}
public static function getConfigurationFile(): string
{
return __DIR__ . '/MenuDashboard.xml';
}
public function aggregateData(ADashboardEntity|DashboardEntity &$entity)
{
$entity->price = $this->calculateTotalPrice();
$entity->discount = $this->getAttributeValue('menu_discount');
$entity->nb_plats = count($this->getAttributeValue(MenuFields::menu_plat));
$entity->creation = DateTime::createFromFormat("Y-m-d H:i:s.u", substr($this->cdate, 0, 26));
}
private function calculateTotalPrice(): float
{
$consumables = array_merge(
array_values($this->getAttributeValue(MenuFields::menu_plat)),
array_values($this->getAttributeValue(MenuFields::menu_boisson))
);
$discount = $this->getAttributeValue(MenuFields::menu_discount);
$totalPrice = 0;
foreach ($consumables as $value) {
$smartElement = SEManager::getDocument($value);
if (!is_null($smartElement)) {
$smartField = $smartElement->getAttributeValue(ConsommableFields::consommable_price_incl_vat);
if (!is_null($smartField)) {
$totalPrice += smartField;
}
}
}
return $totalPrice * (1 - $discount / 100);
}
}
# Et ensuite ?
Pour chacune des Smart Structures implémentant l'interface IDashboardElement
, l'ETL va être chargé de maintenir à jour
la table définie dans <smartStructure>Behavior::getConfigurationFile()
. Pour chacun des Smart Element de ces Smart
Structures, aggregateData()
lui fournira les données à insérer dans la table concernée.
# Limitations et solutions
Attention
L'ETL met à jour les métriques des Smart Elements concernés en fonction de leur mdate
: les métriques sont recalculées
uniquement si le Smart Element est plus récent au sens de mdate
.
Reprenons l'exemple du How To. En l'état, si un des plats du menu est modifié le prix total ne sera pas recalculé tant que le menu lui-même n'aura pas été édité.
Deux solutions peuvent être envisagées :
- utiliser des Smart Field étendus
- enregistrer une méthode sur les hooks des Smart Elements
plat
qui mettrait à jour la date de modification,mdate
, de tous les menus y faisant référence
Exemple :
<?php
namespace Cogip\Restauratec\SmartStructures\Plat;
use Anakeen\Core\Utils\Date;
use Anakeen\Search\Filters\ContainsValues;
use Anakeen\Search\SearchElements;
use Anakeen\SmartHooks;
class PlatBehavior extends \Anakeen\SmartElement
{
public function registerHooks()
{
parent::registerHooks();
$updateRelatedMenu = function () {
$search = new SearchElements('MENU');
$search->setLatest(true);
$search->addFilter(new ContainsValues(\SmartStructure\Fields\Menu::menu_plat, strval($this->initid)));
$res = $search->getResults();
foreach ($res as $se) {
$se->mdate = Date::getNow(true);
$se->modify();
}
};
$this->getHooks()->addListener(SmartHooks::POSTSTORE, $updateRelatedMenu);
$this->getHooks()->addListener(SmartHooks::POSTREVISE, $updateRelatedMenu);
$this->getHooks()->addListener(SmartHooks::POSTDELETE, $updateRelatedMenu);
$this->getHooks()->addListener(SmartHooks::POSTUNDELETE, $updateRelatedMenu);
}
}
Ici, lorsqu'un plat est modifié, tous les menus qui le contiennent voient leur date de modification (mdate) mise à jour. Ces menus sont alors traités à nouveau par l'ETL, assurant ainsi que leur prix est toujours à jour dans la base de donnée dédiée au module Dashboard.