# 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 = ...;
        ...
    }
}

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 classe ADashboardEntity. 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 :

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.