diff --git a/doc/serveur.md b/doc/serveur.md index 485b3cb5c308e356b463cfa2324503ce253091df..0e2d2ef8750f44b2b943628667f00fa1fa4ae3db 100644 --- a/doc/serveur.md +++ b/doc/serveur.md @@ -112,9 +112,9 @@ Ce dernier va : - collecter les éventuels messages issus du `flashMessenger` - convertir le tout en Json pour envoi au client -AxiosModel peut prendre en construction kjusqu'à 3 paramètres : +AxiosModel peut prendre en construction jusqu'à 3 paramètres (facultatifs): 1. Les données en tant que telles -2. Les prioriétés (utiles seulement si on traite des objets et facultatives si on transmet des objets implémentant AxiosInterface) +2. Les propriétés (utiles seulement si on traite des objets et facultatives si on transmet des objets implémentant AxiosInterface) 3. Les triggers (si nécessaire). Vous trouverez [plus d'infos sur les triggers ici](#les-triggers). Voici un exemple d'action de contrôleur qui envoie des données au client en mode Ajax vers Axios : @@ -134,28 +134,56 @@ use UnicaenVue\View\Model\AxiosModel; ], ]; - // Petit msg d'info + // Petit message d'info à afficher sous forme de Toast $this->flashMessenger()->addSuccessMessage('Tout va bien!'); // Et on retourne un AxiosModel qui présente le tout au client // Ici, nous traitons un tableau en entrée, donc pas besoin de préciser des propriétés à extraire et nous n'avons pas besoin de triggers return new AxiosModel($contacts[$monId]); - // Si on exporte un objet ou un tableau d'objets, on peut aussi fournir une lisye de propriétés, cf. ExiosExtractor + // Si on exporte un objet ou un tableau d'objets, on peut aussi fournir une liste de propriétés, cf. ExiosExtractor // $proprietes = [/* liste des propriétés à exporter */]; // => return new AxiosModel($monObjet, $proprietes); } ``` +Si vous n'avez besoin de ne renvoyer que le premier item d'une liste et que l'AxiosModel renvoie une liste, +alors vous pouvez faire comme dans l'exemple suivant : +```php + +// On crée dans $query une requête de type Doctrine\Orm\Query +$entityManager = ... // Votre entityManager +$dql = "... votre requête DQL"; +$query = $entityManager->createQuery($dql); + +// Création du modèle Axios +$model = new AxiosModel; + +// on peut aussi passer les données (ou Query) et les propriétés avec des accesseurs +$model->setData($query); +$model->setProperties($properties); + +$properties = [ + ... // La liste de vos propriétés à retourner +]; + +// La ligne ci-dessous fera que l'AxiosRenderer ne renverra que le premier item du résultat de votre requête +$model->returnFirstItem(); + +return $model; + +``` ## AxiosExtractor -L'AxiosExtractor est chargé de convertir des données en PHP issues du serveur afin de pouvoir les réexploiter sur le client, en Javascript. +L'AxiosExtractor est chargé de convertir des données en PHP issues du serveur afin de pouvoir les ré-exploiter sur le client, en Javascript. + +Il n'a pas besoin d'être appelé explicitement, hors cas d'usage spécifique. -Il n'a pas besoin d'être appelé explicitement, hors cas d'usage spécifique. Il est appelé en arrière-plan lorsque vous retournez un `AxiosModel`, un `VueModel` ou faites appel à l'aide de vue `vue`. +En temps normal, vous pourrez vous borner à retourner des AxiosModel dans des actions de contrôleurs. Au besoin, il faudra appeler la méthode globale `\UnicaenVue\Axios\AxiosExtractor::extract`. @@ -333,6 +361,8 @@ Si des propriétés sont explicitement transmises en second paramètre d'extract A défaut, AxiosExtractor peut extraire la liste des propriétés si les objets implémentent `UnicaenVue\Axios\AxiosExtractorInterface` Cela peut être utile pour des objets dont nous avons toujours besoin de renvoyer les mêmes propriétés. +Dans la mesure du possible, évitez de l'utiliser et privilégiez la fourniture explicite de "properties" au moment de l'extraction de données. +Cela facilitera la compréhension de votre code. A l'exemple ci-dessus, on ajoute à la classe Adresse : @@ -374,6 +404,8 @@ Ce sera utile si, par exemple, on veut ajouter des propriétés à la volée à après coup la valeur de certaines données. Il s'agit d'un usage avancé du dispositif. +A n'utiliser, donc, qu'à défaut de meilleure solution. +L'idéal est de fournir des entités créées spécifiquement pour répondre à vos besoins d'extraction. Les triggers sont un tableau de fonctions dont les clés sont les chemins qui vont permettre de déterminer sur quelles données nous voudrons agir, et les valeurs sont des fonctions anonymes dotées de deux paramètres $original : les données originales, c'est-à-dire avant extractions et $extracted, c'est-à-dire le résultat extrait de l'original. @@ -487,7 +519,44 @@ $dql = " // Ici, les propriétés ne sont pas définies, dont l'entité Mission doit implémenter `UnicaenVue\Axios\AxiosExtractorInterface` // Idem pour les autres entités remontées. // Les donnnées transmises au client seront une liste de missions, avec toutes les données et sous-entités afférentes converties en objets JSON - return new AxiosModel($query); + + // les properties sont définies ici + $utilisateurProperties = ['id','email','displayName']; + + $properties = [ + "id", + // Pour le type de mission, on ne renverra que "id" et "libelle" + ['typeMission',['id','libelle']], + 'dateDebut', + 'dateFin', + ['structure',['id','libelle']], + ['tauxRemu',['id','libelle']], + 'description', + 'histoCreation', + ['histoCreateur',$utilisateurProperties], + 'heures', + 'heuresValidees', + ['volumesHoraires',[ + 'id', + 'heures', + 'valide', + 'validation', + 'histoCreation', + ['histoCreateur',$utilisateurProperties], + 'canValider', + 'canDevalider', + 'canSupprimer', + ]], + 'contrat', + 'valide', + 'validation', + 'canSaisie', + 'canValider', + 'canDevalider', + 'canSupprimer', + ]; + + return new AxiosModel($query, $properties); ``` Et voici le résultat final récupéré dans le composant Vue avec Axios : diff --git a/src/Axios/AxiosExtractor.php b/src/Axios/AxiosExtractor.php index d1f8d0efd03408044df8e386abf410cddc3e5395..eae0bb2f1bc0ad6b66c6df04626f452769f488b4 100644 --- a/src/Axios/AxiosExtractor.php +++ b/src/Axios/AxiosExtractor.php @@ -14,6 +14,7 @@ class AxiosExtractor protected array $triggers = []; + public static function extract($data, array $properties = [], array $triggers = []) { $axios = new self; @@ -42,7 +43,7 @@ class AxiosExtractor $result = $data; } - if (array_key_exists($triggerPath, $this->triggers) && !$data instanceof Query){ + if (array_key_exists($triggerPath, $this->triggers) && !$data instanceof Query) { // trigger est un callable qui accepte deux arguments : le premier les la donnée originale, le second la donnée extraite // il doit retourner une donnée qui remplacera la donnée extraite $result = $this->triggers[$triggerPath]($data, $result); @@ -56,35 +57,21 @@ class AxiosExtractor protected function extractObject($data, array $properties, string $path = ''): array { // contrôle de boucle récursive, afin de ne pas saturer la mémoire... - if (substr_count($path, '/') >= self::$loopControl){ + if (substr_count($path, '/') >= self::$loopControl) { //return []; - throw new \Exception("AxiosExtractor has detected a possible infinite loop, and aborted your script with a stack depth of '".self::$loopControl."' frames"); + throw new \Exception("AxiosExtractor has detected a possible infinite loop, and aborted your script with a stack depth of '" . self::$loopControl . "' frames"); } $result = []; - $props = ['id']; - if (empty($properties)) { - if ($data instanceof AxiosExtractorInterface) { - $ad = $data->axiosDefinition(); - foreach ($ad as $prop) { - if ($prop !== 'id') { - $props[] = $prop; - } - } - } - } else { - foreach ($properties as $prop) { - if ($prop !== 'id') { - $props[] = $prop; - } - } + if (empty($properties) && $data instanceof AxiosExtractorInterface) { + $properties = $data->axiosDefinition(); } - foreach ($props as $property) { + foreach ($properties as $property) { if (is_array($property)) { $subProperties = $property[1]; - $property = $property[0]; + $property = $property[0]; } else { $subProperties = []; } @@ -97,8 +84,8 @@ class AxiosExtractor ]; foreach ($methods as $method) { if (method_exists($data, $method)) { - $value = $data->$method(); - $result[$property] = $this->extractData($value, $subProperties, $path.'/'.$property); + $value = $data->$method(); + $result[$property] = $this->extractData($value, $subProperties, $path . '/' . $property); break; } } @@ -113,27 +100,20 @@ class AxiosExtractor { $result = []; - - $props = ['id']; if (empty($properties)) { $properties = array_keys($data); } - foreach ($properties as $prop) { - if ($prop !== 'id') { - $props[] = $prop; - } - } - foreach ($props as $property) { + foreach ($properties as $property) { if (is_array($property)) { $subProperties = $property[1]; - $property = $property[0]; + $property = $property[0]; } else { $subProperties = []; } if (array_key_exists($property, $data)) { - $result[$property] = $this->extractData($data[$property], $subProperties, $path.'/'.$property); + $result[$property] = $this->extractData($data[$property], $subProperties, $path . '/' . $property); } } diff --git a/src/View/Model/AxiosModel.php b/src/View/Model/AxiosModel.php index 2a2d0fb22b34ffdba5749327ce40fe8b20a7f58a..8cfbe9595aa2b76954c7b5a388cf10d0ce577434 100644 --- a/src/View/Model/AxiosModel.php +++ b/src/View/Model/AxiosModel.php @@ -8,7 +8,9 @@ use Traversable; class AxiosModel implements ModelInterface { - protected $data; + protected $data = null; + + protected bool $returnFirstItem = false; protected array $properties = []; @@ -16,11 +18,11 @@ class AxiosModel implements ModelInterface - public function __construct($data, array $properties = [], array $triggers = []) + public function __construct($data = null, array $properties = [], array $triggers = []) { - $this->data = $data; + $this->data = $data; $this->properties = $properties; - $this->triggers = $triggers; + $this->triggers = $triggers; } @@ -73,6 +75,20 @@ class AxiosModel implements ModelInterface + public function returnFirstItem(bool $returnFirstItem = true) + { + $this->returnFirstItem = $returnFirstItem; + } + + + + public function isReturnFirstItem(): bool + { + return $this->returnFirstItem; + } + + + public function getVariables() { return $this->data; @@ -107,77 +123,77 @@ class AxiosModel implements ModelInterface public function setOption($name, $value) { - // TODO: Implement setOption() method. + throw new \Exception('setOption is not available with AxiosModel'); } public function getVariable($name, $default = null) { - // TODO: Implement getVariable() method. + throw new \Exception('getVariable is not available with AxiosModel'); } public function setVariable($name, $value) { - // TODO: Implement setVariable() method. + throw new \Exception('setVariable is not available with AxiosModel'); } public function setTemplate($template) { - // TODO: Implement setTemplate() method. + // do nothing, no templates needed } public function getTemplate() { - // TODO: Implement getTemplate() method. + // do nothing, no templates needed } public function addChild(ModelInterface $child, $captureTo = null, $append = false) { - // TODO: Implement addChild() method. + // no nothing : AxiosModel does not support children } public function getChildren() { - // TODO: Implement getChildren() method. + return []; } public function hasChildren() { - // TODO: Implement hasChildren() method. + return false; } public function setCaptureTo($capture) { - // TODO: Implement setCaptureTo() method. + throw new \Exception('setCaptureTo is not available with AxiosModel'); } public function captureTo() { - // TODO: Implement captureTo() method. + throw new \Exception('captureTo is not available with AxiosModel'); } public function setTerminal($terminate) { - + throw new \Exception('setTerminal is not available with AxiosModel'); } @@ -191,21 +207,21 @@ class AxiosModel implements ModelInterface public function setAppend($append) { - // TODO: Implement setAppend() method. + throw new \Exception('setAppend is not available with AxiosModel'); } public function isAppend() { - // TODO: Implement isAppend() method. + throw new \Exception('isAppend is not available with AxiosModel'); } public function getIterator() { - // TODO: Implement getIterator() method. + throw new \Exception('getIterator is not available with AxiosModel'); } diff --git a/src/View/Renderer/AxiosRenderer.php b/src/View/Renderer/AxiosRenderer.php index 4b20f9557ca5cc2949efdcbcd4623fb1a51d2b0f..0d6ce3b8972ab74f88ac94f8720db5cfe14caccb 100755 --- a/src/View/Renderer/AxiosRenderer.php +++ b/src/View/Renderer/AxiosRenderer.php @@ -35,6 +35,10 @@ class AxiosRenderer extends JsonRenderer { $data = AxiosExtractor::extract($axiosModel->getData(), $axiosModel->getProperties(), $axiosModel->getTriggers()); + if (is_array($data) && $axiosModel->isReturnFirstItem()){ + $data = reset($data); + } + $namespaces = [ $this->flashMessenger::NAMESPACE_SUCCESS, $this->flashMessenger::NAMESPACE_WARNING,