# Comportement des Smart Structures
L'association d'une classe de comportement permet d'enrichir les fonctionnalités d'un Smart Element. Elle permet d'ajouter des fonctions supplémentaires pour calculer des valeurs ou pour réaliser des traitements spécifiques. Elle permet aussi de modifier le comportement des fonctions standards en enregistrant des hooks sur ces fonctions standards telle que la modification ou la création de Smart Element.
# Déclarer une classe de comportement
La classe de comportement doit être déclarée dans la balise structure-configuration/class/
. Cette référence indique le
nom complet de la classe avec son namespace.
Le fichier décrivant la classe doit être placé sous le répertoire vendor
en respectant la norme
PSR-4.
Si la structure définie n'a pas de parent alors la classe doit étendre la classe Anakeen\SmartElement
. Si la structure
contient un héritage, alors la classe doit étendre la classe du parent soit : SmartStructure\<Structureparentname>
WARNING
Le nom de classe héritée à mettre le fichier PHP référence la structure parente. Elle doit être en minuscules sauf la première lettre qui doit être en majuscule.
Système
Pour chaque Smart Structure enregistrée, une classe PHP est construite. Cette classe PHP est nommée
SmartStructure\<Structurename>
. Structurename
est le nom de la structure en minuscules avec la première lettre en
majuscule. Cette classe est enregistrée dans le répertoire <contextInstall>/var/SmartClasses/SmartStructure
. Le
répertoire <contextInstall>/var/SmartClasses/
est déclaré comme répertoire racine de
PSR-4. Le fichier de cette classe est nommé Structurename.php
.
De plus, une classe contenant les noms des Smart Fields sous forme de constantes est aussi construite. Cette classe PHP
est nommée SmartStructure\Fields\<Structurename>
. Elle est enregistrée dans le répertoire
<contextInstall>/var/SmartClasses/SmartStructure/Fields
# Exemple sans héritage :
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_STRUCTURE" label="Ma structure">
<smart:class>My\SmartStructures\MyStructure\MyStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="my_fr_info" type="frame" label="Information" access="ReadWrite">
<smart:field-text name="my_title" label="Titre" access="ReadWrite" needed="true" is-title="true"/>
</smart:field-set>
</smart:fields>
</smart:structure-configuration>
</smart:config>
Fichier de comportement vendor/My/SmartStructures/MyStructure/MyStructureBehaviour.php
namespace My\SmartStructures\MyStructure;
class MyStructureBehaviour extends \Anakeen\SmartElement
{
}
# Exemple avec héritage :
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_BIGSTRUCTURE" label="Ma structure">
<smart:extends ref="MY_STRUCTURE"/>
<smart:class>My\SmartStructures\MyBigStructure\MyBigStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="my_fr_info" extended="true">
<smart:field-date name="my_date" label="Date" access="Read" />
</smart:field-set>
</smart:fields>
</smart:structure-configuration>
</smart:config>
Fichier de comportement vendor/My/SmartStructures/MyBigStructure/MyBigStructureBehaviour.php
namespace My\SmartStructures\MyBigStructure;
class MyBigStructureBehaviour extends \SmartStructure\My_structure
{
}
Ici, c'est bien \SmartStructure\My_structure
qui est utilisé pour indiquer l'héritage de classe vers la structure dont
le nom est MY_STRUCTURE
.
# Les hooks des Smart Elements
Les principales méthodes d'un Smart Element déclenchent du code spécifique qui est enregistré dans la classe de comportement de la Smart Structure.
Code - Hook | Déclenché par la méthode |
---|---|
Anakeen\SmartHooks\PRESTORE | Anakeen\SmartElement::store() |
Anakeen\SmartHooks\POSTSTORE | Anakeen\SmartElement::store() |
Anakeen\SmartHooks\PRECREATED | Anakeen\SmartElement::store() |
Anakeen\SmartHooks\POSTCREATED | Anakeen\SmartElement::store() |
Anakeen\SmartHooks\PREIMPORT | ImportSingleDocument::import() |
Anakeen\SmartHooks\POSTIMPORT | ImportSingleDocument::import() |
Anakeen\SmartHooks\PREREVISE | Anakeen\SmartElement::revise() |
Anakeen\SmartHooks\POSTREVISE | Anakeen\SmartElement::revise() |
Anakeen\SmartHooks\PREUNDELETE | Anakeen\SmartElement::undelete() |
Anakeen\SmartHooks\POSTUNDELETE | Anakeen\SmartElement::undelete() |
Anakeen\SmartHooks\PREDELETE | Anakeen\SmartElement::delete() |
Anakeen\SmartHooks\POSTDELETE | Anakeen\SmartElement::delete() |
Anakeen\SmartHooks\PREDUPLICATE | Anakeen\SmartElement::duplicate() |
Anakeen\SmartHooks\POSTDUPLICATE | Anakeen\SmartElement::duplicate() |
Anakeen\SmartHooks\PREAFFECT | Anakeen\SmartElement::affect() |
Anakeen\SmartHooks\POSTAFFECT | Anakeen\SmartElement::affect() |
Anakeen\SmartHooks\PREREFRESH | Anakeen\SmartElement::refresh() |
Anakeen\SmartHooks\POSTREFRESH | Anakeen\SmartElement::refresh() |
Anakeen\SmartHooks\POSTSTRUCTUREIMPORT | Anakeen\SmartStructure::hook::postImport() |
# Création de Smart Element
Lors de la création avec Anakeen\SmartElement::store()
, les hooks appelés sont :
Anakeen\SmartHooks::PRESTORE
Anakeen\SmartHooks::PRECREATED
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Anakeen\SmartHooks::POSTCREATED
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::POSTSTORE
# Modification de Smart Element
Lors de la modification avec Anakeen\SmartElement::store()
, les hooks appelés sont :
Anakeen\SmartHooks::PRESTORE
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::POSTSTORE
{#core-ref:10c4622a-8834-4b9b-94ba-93f278d9bde0}
# Suppression de Smart Element
Lors de la suppression avec Anakeen\SmartElement::delete()
, les hooks appelés sont :
Anakeen\SmartHooks::PREDELETE
Anakeen\SmartHooks::POSTDELETE
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Lors de la restauration avec Anakeen\SmartElement::undelete()
, les hooks appelés sont :
Anakeen\SmartHooks::PREUNDELETE
Anakeen\SmartHooks::POSTUNDELETE
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
# Duplication de Smart Element
Lors de la duplication avec Anakeen\SmartElement::duplicate()
, les hooks appelés sont :
Anakeen\SmartHooks::PREDUPLICATE
Anakeen\SmartHooks::PRECREATED
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Anakeen\SmartHooks::POSTCREATED
Anakeen\SmartHooks::POSTDUPLICATE
# Révision d'un Smart Element
Lors de la modification avec Anakeen\SmartElement::revise()
, les hooks appelés sont :
Anakeen\SmartHooks::PREREVISE
Anakeen\SmartHooks::PRECREATED
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::POSTREVISE
# Importation d'un Smart Element
Les hooks appelés lors de l'importation d'un Smart Element sont :
Avec création de Smart Element
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::PREIMPORT
Anakeen\SmartHooks::PRECREATED
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Anakeen\SmartHooks::POSTCREATED
Anakeen\SmartHooks::PRESTORE
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::POSTSTORE
Anakeen\SmartHooks::POSTIMPORT
Avec mise à jour de Smart Element
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::PREAFFECT
Anakeen\SmartHooks::POSTAFFECT
Anakeen\SmartHooks::PREIMPORT
Anakeen\SmartHooks::PRESTORE
Anakeen\SmartHooks::PREREFRESH
Anakeen\SmartHooks::POSTREFRESH
Anakeen\SmartHooks::POSTSTORE
Anakeen\SmartHooks::POSTIMPORT
# Enregistrer des méthodes sur les hooks des Smart Elements
L'enregistrement des hooks se fait dans la classe de comportement en surchargeant la méthode registerHooks
. Dans cette
méthode, l'appel à la méthode ->getHooks()->addListener()
permet d'enregistrer de nouvelles callbacks.
L'appel à la méthode parent peut être fait pour ne pas perdre les éventuels hooks définis dans les structures parentes.
L'objet de la classe SmartElementHooks
fournie par la méthode getHooks()
fournit aussi les méthodes suivantes pour
gérer des cas particuliers.
SmartElementHooks::getListeners()
: liste toutes les callback déjà enregistrés (indexé par le nom du hook)SmartElementHooks::removeListeners($hookName)
: supprime les callback déjà enregistrés pour le hook donnéSmartElementHooks::resetListeners()
: supprime tous les callback déjà enregistrésSmartElementHooks::trigger($hookName)
: déclenche les callback enregistrés pour le hook donné
Les callback sont exécutées dans l'ordre où elles ont été enregistrées.
# Exemple calcul d'un Smart Field :
Le Smart Field my_date
contiendra la date du jour à chaque enregistrement.
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_STRUCTURE" label="Ma structure">
<smart:class>My\SmartStructures\MyStructure\MyStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="my_fr_info" type="frame" label="Information" access="ReadWrite">
<smart:field-text name="my_title" label="Titre" access="ReadWrite" needed="true" is-title="true"/>
<smart:field-date name="my_date" label="Date" access="Read" />
</smart:field-set>
</smart:fields>
</smart:structure-configuration>
</smart:config>
Fichier de comportement vendor/My/SmartStructures/MyStructure/MyStructureBehaviour.php
namespace My\SmartStructures\MyStructure;
use SmartStructure\Fields\MyStructure as MyStructureFields;
use Anakeen\SmartHooks;
class MyStructureBehaviour extends \Anakeen\SmartElement
{
public function registerHooks()
{
parent::registerHooks();
$this->getHooks()->addListener(SmartHooks::PRESTORE, function () {
$this->setValue(MyStructureFields::my_date, date("Y-m-d"));
});
}
}
# Les hooks des Smart Fields
Il est possible de mettre en place, au travers des Hooks, des méthodes permettant de contrôler les données d'un Smart
Element afin de valider ou non l'enregistrement, on parle alors de contrainte
ou bien de calculer la valeur d'un Smart
Field à partir d'autres données, on parle alors d'un Smart Field calculé.
La déclaration des hooks des Smart Fields est faite dans la balise structure-configuration/hooks/field-hook
.
L'attribut structure-configuration/hooks/field-hook/field-callable/@function
peut référencer :
- une méthode statique (
Namespace\Class::method
) - une classe avec une méthode
__invoke
statique (Namespace\Class
) - une méthode de la classe de comportement (
::method
)
Cette méthode callable
est appelée au déclenchement de l'évènement du hook défini.
L'attribut structure-configuration/hooks/field-hook/field-argument/@type
peut avoir les valeurs suivantes :
string
: la valeur de l'argument est le contenu de la balisefield-argument
field
: le contenu de la balisefield-argument
référence un Smart Field, la valeur de l'argument est la valeur du Smart Fieldproperty
: le contenu de la balisefield-argument
référence une propriété, la valeur de l'argument est la valeur de la propriété.index
: Dans le cas où le Smart Field est dans un tableau, cela donne la rangée dans le tableau (0 étant la première rangée). Le contenu de la balisefield-argument
est vide.this
: Retourne l'objet PHP "SmartElement" courant. Le contenu de la balisefield-argument
est vide.
# Exemple d'une contrainte de Smart Field
Une contrainte permet d'empêcher l'enregistrement d'un Smart Element si les conditions fonctionnelles ne sont pas réunies. Les contraintes sont vérifiées lors de l'appel la méthode :
public function store(&$info = null, $skipConstraint = false)
Le deuxième argument, s'il est positionné à true
permet d'enregistrer sans vérification de contrainte.
Une méthode de contrainte callable
doit être définie et doit retourner null
, chaîne vide ""
ou true
pour
indiquer que la contrainte est respectée. La méthode retourne une chaîne de caractères non vide pour indiquer la raison
de l'échec. La méthode peut retourner false
pour mettre en échec sans donner de raison.
Fichier PHP de contrainte vendor/My/Utils/Mail.php
namespace My\Utils;
class Mail
{
public static function checkMailAddress(string $email): string
{
if ($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return "The email address is not valid";
}
}
return "";
}
}
La déclatation de la contrainte doit être effectuée dans la balise field-hook
, les attributs à définir sont :
type
: égal àconstraint
event
: égal àonPreStore
field
: nom du Smart Field où se porte la contrainte
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_STRUCTURE" label="Ma structure">
<smart:class>My\SmartStructures\MyStructure\MyStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="my_fr_info" type="frame" label="Information" access="ReadWrite">
<smart:field-text name="my_title" label="Titre" access="ReadWrite" needed="true" is-title="true"/>
<smart:field-text name="my_email" label="Adresse courriel" access="ReadWrite" />
</smart:field-set>
</smart:fields>
<smart:hooks>
<smart:field-hook type="constraint" event="onPreStore" field="my_email">
<smart:field-callable function="My\Utils\Mail::checkMailAddress"/>
<smart:field-argument type="field">my_email</smart:field-argument>
</smart:field-hook>
</smart:hooks>
</smart:structure-configuration>
</smart:config>
# Exemple d'une contrainte sur une colonne de tableau
Il est possible d'utiliser une contrainte sur une colonne de tableau. Dans ce cas, la contrainte sera déclenchée une fois par ligne.
WARNING
Il est impossible d'utiliser un tableau en argument d'une contrainte.
Fichier PHP de contrainte vendor/My/Utils/Number.php
namespace My\Utils;
class Number
{
public static function checkAscendingNumbers(int number_1, int number_2): string
{
if ($number_1 > $number_2) {
return "Le nombre 1 est supérieur au nombre 2";
}
return "";
}
}
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_STRUCTURE" label="Ma structure">
<smart:class>My\SmartStructures\MyStructure\MyStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="numbers_frame" type="frame" access="ReadWrite" label="Des nombres">
<smart:field-set name="numbers_array" type="array" access="ReadWrite">
<smart:field-int access="ReadWrite" name="number_1" label="Nombre 1"/>
<smart:field-int access="ReadWrite" name="number_2" label="Nombre 2"/>
</smart:field-set>
</smart:field-set>
</smart:fields>
<smart:hooks>
<smart:field-hook type="constraint" event="onPreStore" field="number_1">
<smart:field-callable function="My\Utils\Number::checkAscendingNumbers"/>
<smart:field-argument type="field">number_1</smart:field-argument>
<smart:field-argument type="field">number_2</smart:field-argument>
</smart:field-hook>
</smart:hooks>
</smart:structure-configuration>
</smart:config>
# Exemple d'un Smart Field calculé
Un Smart Field calculé est un Smart Field dont la valeur est calculée par Anakeen Platform. Ce calcul est effectué par
l'intermédiaire d'une méthode callable
appelée suite au déclenchement d'un hook spécifique, défini dans la
configuation de la Smart Structure
La déclaration est faite dans la balise structure-configuration/hooks/field-hook
.
<smart:config xmlns:smart="https://platform.anakeen.com/4/schemas/smart/1.0">
<smart:structure-configuration name="MY_STRUCTURE" label="Ma structure">
<smart:class>My\SmartStructures\MyStructure\MyStructureBehaviour</smart:class>
<smart:fields>
<smart:field-set name="my_fr_info" type="frame" label="Information" access="ReadWrite">
<smart:field-text name="my_title" label="Titre" access="ReadWrite" needed="true" is-title="true"/>
<smart:field-text name="my_email" label="Adresse courriel" access="ReadWrite" />
<smart:field-text name="my_first_name" label="Adresse courriel" access="ReadWrite" />
<smart:field-text name="my_last_name" label="Adresse courriel" access="ReadWrite" />
<smart:field-text name="my_complete_name" label="Adresse courriel" access="ReadWrite" />
</smart:field-set>
</smart:fields>
<smart:hooks>
<smart:field-hook event="onPreRefresh" field="my_complete_name">
<smart:field-callable function="::calculateCompleteName"/>
</smart:field-hook>
</smart:hooks>
</smart:structure-configuration>
</smart:config>
Méthode PHP définie dans la classe définissant le comportement My\SmartStructures\MyStructure\MyStructureBehaviour
public function calculateCompleteName(): float
{
$fname = $this->getAttributeValue(MyStructureFields::my_first_name);
$lname = $this->getAttributeValue(MyStructureFields::my_last_name);
$completeName = $fname . ' '. $lname;
return $completeName;
}