Comment ajouter des données à visualiser ?

Prérequis

Afin de pouvoir suivre ce guide, il faut préalablement avoir créé une ou plusieurs Smart Structure(s). Il est également nécessaire d'avoir préparé l'environnement.

Définir des métriques sur une Smart Structure existante

Reprenons l'exemple de la Smart Structure Menu. Nous souhaitons analyser et visualiser les métriques suivantes dans nos tableaux de bord :

  • prix du menu
  • remise
  • nombre de plats

Définition des métriques

Dans un premier temps, créons un nouveau fichier de configuration renseignant la liste de ces indicateurs ainsi que leur type :

src/vendor/Cogip/Restauratec/SmartStructures/Menu/MenuDashboard.xml

<?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>

Nous ajoutons également un champ creation pour sauvegarder la date de création de chacun de nos menus, et ainsi pouvoir visualiser l'évolution de nos métriques au cours du temps.

Informations

Ce fichier décrit la structure de la table qui sera créée dans la base de données dédiée à Superset. Pour consulter la liste des types et options disponibles consulter le manuel de référence.

Attention

Pensez à déployer vos modifications locales sur le serveur et à générer les stubs :

make deploy
make generate-stubs

Définition du calcul des métriques

Dans un premier temps, lions notre fichier de configuration à la Smart Structure Menu. Pour cela, étendons la classe MenuBehavior en implémentant l'interface IDashboardElement.

src/vendor/Cogip/Restauratec/SmartStructures/Menu/MenuBehavior.php





 
 

 






 
 
 
 
 
 


<?php

namespace Cogip\Restauratec\SmartStructures\Menu;

use Anakeen\Dashboard\IDashboardElement;
use Anakeen\Dashboard\ADashboardEntity;

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) {}
}

getConfigurationFile() doit retourner le chemin du fichier de configuration précédemment créé.

Il faut maintenant définir la façon dont ces métriques vont être calculées. Pour ce faire, implémentons la fonction aggregateData().

src/vendor/Cogip/Restauratec/SmartStructures/Menu/MenuBehavior.php







 
 
 















 
 
 
 


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


<?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);
    }
}

aggregateData() doit définir comment sont calculés les indicateurs par rapport au Smart Element concerné. Le calcul des indicateurs est réalisé de manière asynchrone par les workers de l'ETL, il est donc possible d'effectuer des calculs bien plus complexes et coûteux que ceux présentés dans ce guide sans pour autant surcharger notre application.

Attention

Il est nécessaire de renseigner chaque champ qui n'a pas été défini comme nullable dans le fichier de configuration.

Attention

Pensez à déployer vos modifications locales sur le serveur.

make deploy

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.

En l'état, si le prix d'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é. Une solution possible est de modifier automatiquement le mdate des menus concernés par le changement de prix d'un plat donné. Pour ce faire, enregistrons une méthode qui sera appelée à chaque modification d'un Smart Element Plat :

src/vendor/Cogip/Restauratec/SmartStructures/Plat/PlatBehavior.php





 
 
 
 






 
 
 
 
 
 
 
 
 
 
 
 
 
 



<?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);
  }
}

Désormais 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.

Recommandation

Modifiez de la même façon BoissonBehavior.

Informations

Une autre solution est la définition de champs étendus. À partir de la version 2023.01

Importation des données

Pour mettre à jour les schémas des données traitées par l'ETL il suffit de redémarrer l'environnement :

make env-stop
make env-start

Désormais, l'ETL va maintenir à jour une nouvelle table menu avec le prix, la date de création, la remise ainsi que le nombre de plats de chacun des Smart Elements Menu.

Recommandation

Pensez à créer quelques Smart Elements :

Attention

Le traitement est asynchrone. Par défaut l'actualisation a lieu toutes les minutes.

Et ensuite ?

Comment créer un tableau de bord ?