À partir de la version 2023.1.2
Comment définir un champ calculé ?Un champ calculé est calculé automatiquement en fonction d'autres champs du Smart Element. Il est recalculé dynamiquement à chaque modification dans le formulaire qui pourrait l'impacter.
Recommandation
Si vous n’êtes pas familier avec les champs calculés et leur fonctionnement, il est fortement recommandé de lire la documentation associée.
Prérequis
Afin de pouvoir suivre ce guide, il faut préalablement avoir créé une ou plusieurs Smart Structure(s). Il est également recommandé d'avoir défini des champs étendus.
Prérequis techniques
- Anakeen Platform 4 - 2023.1.2
Ajouter un champ calculé
Reprenons l'exemple de la Smart Structure MENU
. Notre menu se compose d'une liste de PLAT
et de BOISSON
. Nous
avons vu comment calculer le prix total du menu automatiquement. Cependant, ce calcul n'a lieu qu'après une modification
du menu et son enregistrement. Nous préférions pouvoir afficher dynamiquement le prix total pendant l'édition.
Définir un champ calculé
Créons une nouvelle Smart Structure COMPUTED_MENU
:
npx @anakeen/anakeen-cli createSmartStructure --sourcePath . --name COMPUTED_MENU
Copions le fichier de configuration de la Smart Structure MENU
et remplaçons le champ menu_price
par un champ
calculé :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="COMPUTED_MENU" label="Menu dynamique">
<smart:icon file="menu.png"/>
<smart:class>Cogip\Restauratec\SmartStructures\ComputedMenu\ComputedMenuBehavior</smart:class>
<smart:fields>
<smart:field-set name="menu_frame" type="frame" access="ReadWrite" label="Informations relatives au menu">
<smart:field-text name="menu_title" needed="true" is-title="true" access="ReadWrite" label="Libellé"/>
<smart:field-htmltext name="menu_description" access="ReadWrite" label="Description"/>
<smart:field-set name="menu_composition" type="array" access="ReadWrite" label="Composition du menu">
<smart:field-docid access="ReadWrite" name="menu_plat" label="Plat" relation="PLAT"/>
<smart:extended-field-money name="menu_plat_price" access="Read" label="Prix du plat" >
<smart:copy relation-field="menu_plat" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
<smart:field-docid access="ReadWrite" name="menu_boisson" label="Boisson" relation="BOISSON"/>
<smart:extended-field-money name="menu_boisson_price" access="Read" label="Prix de la boisson" >
<smart:copy relation-field="menu_boisson" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
</smart:field-set>
<smart:field-double name="menu_discount" access="ReadWrite" label="Remise applicable (%)"/>
<smart:computed-field-money name="menu_price" access="Read" label="Prix (€)"/>
</smart:field-set>
</smart:fields>
<smart:defaults/>
</smart:structure-configuration>
</smart:config>
Informations
Les types de computed-field-<TYPE>
disponibles sont les mêmes que ceux des Smart Fields contenant de la donnée, dont
la liste est disponible
ici,
ainsi qu'un type spécial computed-field-array
dont le fonctionnement sera détaillé dans le chapitre suivant.
Configurer son calcul
Il faut maintenant définir :
- quels champs impactent le prix total (ses dépendances)
- comment calculer le prix total (sa fonction de calcul)
La définition de la fonction de calcul et des dépendances se fait dans une balise computed
. Ajoutons la configuration
suivante :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="COMPUTED_MENU" label="Menu dynamique">
<smart:icon file="menu.png"/>
<smart:class>Cogip\Restauratec\SmartStructures\ComputedMenu\ComputedMenuBehavior</smart:class>
<smart:fields>
<smart:field-set name="menu_frame" type="frame" access="ReadWrite" label="Informations relatives au menu">
<smart:field-text name="menu_title" needed="true" is-title="true" access="ReadWrite" label="Libellé"/>
<smart:field-htmltext name="menu_description" access="ReadWrite" label="Description"/>
<smart:field-set name="menu_composition" type="array" access="ReadWrite" label="Composition du menu">
<smart:field-docid access="ReadWrite" name="menu_plat" label="Plat" relation="PLAT"/>
<smart:extended-field-money name="menu_plat_price" access="Read" label="Prix du plat" >
<smart:copy relation-field="menu_plat" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
<smart:field-docid access="ReadWrite" name="menu_boisson" label="Boisson" relation="BOISSON"/>
<smart:extended-field-money name="menu_boisson_price" access="Read" label="Prix de la boisson" >
<smart:copy relation-field="menu_boisson" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
</smart:field-set>
<smart:field-double name="menu_discount" access="ReadWrite" label="Remise applicable (%)"/>
<smart:computed-field-money name="menu_price" access="Read" label="Prix (€)"/>
</smart:field-set>
</smart:fields>
<smart:defaults/>
<smart:computed>
<smart:field-computed field="menu_price">
<smart:field-callable function="::computeTotalPrice"/>
<smart:field-argument type="field" name="prix_boissons">menu_boisson_price</smart:field-argument>
<smart:field-argument type="field" name="prix_plats">menu_plat_price</smart:field-argument>
<smart:field-argument type="field" name="remise">menu_discount</smart:field-argument>
</smart:field-computed>
</smart:computed>
</smart:structure-configuration>
</smart:config>
Cette configuration indique que le champ calculé menu_price
:
- dépend des valeurs des champs
menu_boisson_price
,menu_plat_price
etmenu_discount
- est calculé via la fonction
computeTotalPrice
À retenir
Les field-argument
sont les dépendances d'un champ calculé et sont passés en argument de la fonction définie par
field-callable/@function
.
Information
Il est également possible de passer comme arguments supplémentaires :
- des propriétés sur le Smart Element (
id
,initid
,fromid
,title
ouviewId
)
<smart:field-argument type="property" name="id">id</smart:field-argument>
- une chaîne de caractères
<smart:field-argument type="string" name="my_string">Une chaine de caracteres</smart:field-argument>
Rendons-nous dans la classe de comportement de la Smart Structure COMPUTED_MENU
est définissons la fonction
computeTotalPrice
. Comme précisé dans la documentation, cette fonction doit respecter la signature suivante :
function (DynamicUpdateRequest $request, DynamicUpdateResponse $response, $args): DynamicUpdateResponse;
où $args
est un tableau contenant comme nous l'avons demandé :
- le prix de toutes les boissons
- le prix de tous les plats
- la remise à appliquer
Définissons notre fonction de calcul du prix total :
<?php
namespace Cogip\Restauratec\SmartStructures\ComputedMenu;
use Anakeen\Core\SmartStructure\Dynamic\DynamicUpdateRequest;
use Anakeen\Core\SmartStructure\Dynamic\DynamicUpdateResponse;
class ComputedMenuBehavior extends \Anakeen\SmartElement
{
public function computeTotalPrice(DynamicUpdateRequest $request, DynamicUpdateResponse $response, $args): DynamicUpdateResponse
{
$total = 0;
$consommablesPrice = array_merge($args['prix_boissons'], $args['prix_plats']);
foreach ($consommablesPrice as $price) {
if ($price !== null) {
$total += $price;
}
}
$total = $total * (1.0 - (floatval($args['remise'] ?? 0) / 100.0));
return $response->setResult($total);
}
}
Informations
L'attribut field-argument/@name
est optionnel, la valeur du champ est alors ajoutée dans $args
sans clé et dans
l'ordre de définition des arguments.
Attention
Pensez à déployer vos modifications.
make deploy
Résultat
Rendons-nous maintenant sur le
formulaire de création d'un
COMPUTED_MENU
.
À chaque ajout ou modification de plat/boisson ou à chaque changement sur le taux de remise, le champ total
est
modifié et mis en évidence :
;
Informations
Vous pouvez également noter que le champ étendu du prix du consommable est également mis à jour de manière dynamique.
Notre menu affiche désormais un prix dynamique 🎉 !
Cas particulier des tableaux
Un champ calculé peut évidemment être intégré dans un tableau. S'il dépend d'autres champs du tableau, il aura à sa disposition, pour son calcul, uniquement la valeur de sa dépendance au même index. Cette dépendance est dite inline.
Ajoutons dans notre exemple un champ calculant la somme du prix du plat et de la boisson par entrée dans le tableau de la composition du menu :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="COMPUTED_MENU" label="Menu dynamique">
<smart:icon file="menu.png"/>
<smart:class>Cogip\Restauratec\SmartStructures\ComputedMenu\ComputedMenuBehavior</smart:class>
<smart:fields>
<smart:field-set name="menu_frame" type="frame" access="ReadWrite" label="Informations relatives au menu">
<smart:field-text name="menu_title" needed="true" is-title="true" access="ReadWrite" label="Libellé"/>
<smart:field-htmltext name="menu_description" access="ReadWrite" label="Description"/>
<smart:field-set name="menu_composition" type="array" access="ReadWrite" label="Composition du menu">
<smart:field-docid access="ReadWrite" name="menu_plat" label="Plat" relation="PLAT"/>
<smart:extended-field-money name="menu_plat_price" access="Read" label="Prix du plat" >
<smart:copy relation-field="menu_plat" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
<smart:field-docid access="ReadWrite" name="menu_boisson" label="Boisson" relation="BOISSON"/>
<smart:extended-field-money name="menu_boisson_price" access="Read" label="Prix de la boisson" >
<smart:copy relation-field="menu_boisson" from-field="consommable_price_excl_vat" />
</smart:extended-field-money>
<smart:computed-field-money name="combined_price" access="Read" label="Somme"/>
</smart:field-set>
<smart:field-double name="menu_discount" access="ReadWrite" label="Remise applicable (%)"/>
<smart:computed-field-money name="menu_price" access="Read" label="Prix (€)"/>
</smart:field-set>
</smart:fields>
<smart:defaults/>
<smart:computed>
<smart:field-computed field="menu_price">
<smart:field-callable function="::computeTotalPrice"/>
<smart:field-argument type="field" name="prix_boissons">menu_boisson_price</smart:field-argument>
<smart:field-argument type="field" name="prix_plats">menu_plat_price</smart:field-argument>
<smart:field-argument type="field" name="remise">menu_discount</smart:field-argument>
</smart:field-computed>
<smart:field-computed field="combined_price">
<smart:field-callable function="::computeCombinedPrice"/>
<smart:field-argument type="field">menu_boisson_price</smart:field-argument>
<smart:field-argument type="field">menu_plat_price</smart:field-argument>
</smart:field-computed>
</smart:computed>
</smart:structure-configuration>
</smart:config>
Définissons maintenant la fonction réalisant la somme des deux prix :
<?php
namespace Cogip\Restauratec\SmartStructures\ComputedMenu;
use Anakeen\Core\SmartStructure\Dynamic\DynamicUpdateRequest;
use Anakeen\Core\SmartStructure\Dynamic\DynamicUpdateResponse;
class ComputedMenuBehavior extends \Anakeen\SmartElement
{
public function computeTotalPrice(DynamicUpdateRequest $request, DynamicUpdateResponse $response, $args): DynamicUpdateResponse
{
$total = 0;
$consommablesPrice = array_merge($args['prix_boissons'], $args['prix_plats']);
foreach ($consommablesPrice as $price) {
if ($price !== null) {
$total += $price;
}
}
$total = $total * (1.0 - (floatval($args['remise'] ?? 0) / 100.0));
return $response->setResult($total);
}
public function computeCombinedPrice(DynamicUpdateRequest $request, DynamicUpdateResponse $response, $args): DynamicUpdateResponse
{
return $response->setResult(($args[0] ?? 0) + ($args[1] ?? 0));
}
}
$args[0]
et $args[1]
sont respectivement le prix de la boisson et le prix du plat à l'index concerné par la
modification. Leur nom d'argument n'ayant pas été spécifié, ils sont fournis sans clé et dans l'ordre fourni par la
configuration.
Redéployons nos changements :
make deploy
Rendons-nous de nouveau sur le
formulaire de création de
COMPUTED_MENU
:
La somme est bien calculée dynamiquement à chaque modification du plat ou du de la boisson sélectionnée, et ce, uniquement sur la ligne concernée.
Et ensuite ?
Continuons sur les champs calculés en nous intéressant aux tableaux calculés.