Comment afficher un message d'erreur lors de l'édition d'un objet

Bonjour à tous,

Je me penche sur le redéveloppement d’un ensemble de plugins que j’avais commis il y a près de deux ans et essaie de faire mieux.

Le premier plugin crée un objet Station et les autres correspondent à des modules qui viennent ajouter des choix au formulaire d’édition des Stations.

L’un des modules insère deux étapes supplémentaires à l’édition d’une Station : la première permet la saisie de données d’authentification et le clic sur le bouton « Suivant » permet d’interroger une API pour proposer une liste de stations.

Dans mes pipelines, j’ai donc la fonction suivante :

function netatmo_formulaire_verifier($flux): array {
	if ($flux['args']['form'] == 'editer_station') {
		// Une fois qu'on a validé la deuxième étape de la création d'une station Netatmo
		if (
			_request('netatmo_client_id') !== null
			&& _request('netatmo_client_secret') !== null
			&& _request('netatmo_access_token') !== null
			&& _request('netatmo_refresh_token') !== null
		) {
			$stations = netatmo_lister_stations_dist(
				_request('netatmo_client_id'),
				_request('netatmo_client_secret'),
				_request('netatmo_access_token'),
				_request('netatmo_refresh_token')
			);

			set_request('netatmo_device_mac', $stations);
		}
	}

	return $flux;
}

La fonction retourne une liste de stations mais en cas d’erreur de saisies des informations de connexion, l’API me renvoie une erreur ; comment procéder pour la faire remonter dans la page d’édition de l’objet, un peu à la manière de ce que fait SVP lors d’un souci d’installation ?

Merci par avance pour vos retours, suggestions, solutions !

Pas certain de bien comprendre, mais tu peux ajouter une erreur au « flux » en faisant un truc comme $flux['data']['unnomdechamp'] = 'mon erreur';.

Je vais essayer d’être plus clair, parce que je ne parviens pas à tirer de la réponse de @b_b de quoi arriver à mes fins.

Le plugin precipitations\core déclare un objet Station et présente le formulaire suivant (fichier editer_station.html vierge, tout est déclaré dans le editer_station.php :

function formulaires_editer_station_saisies_dist($id_station = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
	$saisies = [
		'options' => [
			'afficher_si_avec_post' => true,
		],
		[
			'saisie' => 'fieldset',
			'options' => [
				'nom' => 'definition',
				'label' => _T('station:champ_description_label'),
			],
			'saisies' => [
				[
					'saisie' => 'input',
					'options' => [
						'nom' => 'titre',
						'obligatoire' => 'oui',
						'label' => _T('station:champ_titre_label'),
						'explication' => _T('station:champ_titre_explication'),
					],
				],

				[
					'saisie' => 'selection',
					'options' => [
						'nom' => 'type',
						'obligatoire' => 'oui',
						'label' => _T('station:champ_type_label'),
						'explication' => _T('station:champ_type_explication'),
						'data' => [],
					],
				],
			]
		]
	];
	return $saisies;
}

Le plugin precipitations/modules/netatmo de son côté ajoute quelques champs à la table spip_stations et va « surcharger » le formulaire d’édition des stations via le pipeline formulaire_saisie:

function netatmo_formulaire_saisies($flux): array {
	if ($flux['args']['form'] == 'editer_station') {
		// On ajoute une option dans le select de type de station
		$flux['data'][0]['saisies'][1]['options']['data'] = array_merge($flux['data'][0]['saisies'][1]['options']['data'], ['netatmo' => _T('netatmo:netatmo')]);

		// Ajout des champs nécessaires à la configuration d'un pluvio Netatmo
		include_spip('inc/saisies');

		$flux['data'][] = [
			'saisie' => 'fieldset',
			'options' => [
				'nom' => 'netatmo_authentification',
				'label' => _T('netatmo:champ_netatmo_authentification_label'),
				'afficher_si' => '@type@ == "netatmo"',
				'afficher_si_avec_post' => 'oui',
			],
			'saisies' => [
				[
					'saisie' => 'input',
					'options' => [
						'nom' => 'netatmo_client_id',
						'label' => _T('netatmo:champ_netatmo_client_id_label'),
						'explication' => _T('netatmo:champ_netatmo_client_id_explication'),
						'obligatoire' => 'oui'
					]
				],
				[
					'saisie' => 'input',
					'options' => [
						'nom' => 'netatmo_client_secret',
						'label' => _T('netatmo:champ_netatmo_client_secret_label'),
						'explication' => _T('netatmo:champ_netatmo_client_secret_explication'),
						'obligatoire' => 'oui'
					]
				],
				[
					'saisie' => 'input',
					'options' => [
						'nom' => 'netatmo_access_token',
						'label' => _T('netatmo:champ_netatmo_access_token_label'),
						'explication' => _T('netatmo:champ_netatmo_access_token_explication'),
						'obligatoire' => 'oui',
					]
				],
				[
					'saisie' => 'input',
					'options' => [
						'nom' => 'netatmo_refresh_token',
						'label' => _T('netatmo:champ_netatmo_refresh_token_label'),
						'explication' => _T('netatmo:champ_netatmo_refresh_token_explication'),
						'obligatoire' => 'oui',
					]
				],
			],
		];

		$flux['data'][] =  [
			'saisie' => 'fieldset',
			'options' => [
				'nom' => 'netatmo_choix_station',
				'label' => _T('netatmo:champ_netatmo_choix_station_label'),
				'afficher_si' => '@type@ == "netatmo"',
				'afficher_si_avec_post' => 'oui',
			],
			'saisies' => [
				[
					'saisie' => 'selection',
					'options' => [
						'nom' => 'netatmo_device_id',
						'label' => _T('netatmo:champ_netatmo_device_id_label'),
						'explication' => _T('netatmo:champ_netatmo_device_id_explication'),
						'obligatoire' => 'oui',
						'data' => _request('netatmo_device_mac')
					]
				],
				[
					'saisie' => 'date',
					'options' => [
						'nom' => 'netatmo_debut',
						'label' => _T('station:champ_debut_label'),
						'explication' => _T('station:champ_debut_explication'),
					],
				],
			],
		];

		// On ajoute les options pour le multi-étapes
		$options = $flux['data']['options'];
		if (!is_null(array_keys($options, 'etapes_activer'))) {
			$flux['data']['options'] = ['etapes_activer' => true, 'etapes_ignorer_recapitulatif' => true];
		}
	}

	return $flux;
}

On obtient ainsi un formulaire multi-étapes : en première étape, on sélectionne le type de station, en seconde étape on fournit les informations d’authentification, et enfin, on sélectionne la station souhaitée parmi une liste retournée par l’API Netatmo.

Tout fonctionne bien pour le cas nominal, lorsque l’on a saisi les bonnes informations d’authentification.

Avec le pipeline suivant :

function netatmo_formulaire_verifier($flux): array {
	if ($flux['args']['form'] == 'editer_station') {
		// Une fois qu'on a validé la deuxième étape de la création d'une station Netatmo
		if (
			_request('netatmo_client_id') !== null
			&& _request('netatmo_client_secret') !== null
			&& _request('netatmo_access_token') !== null
			&& _request('netatmo_refresh_token') !== null
		) {
			try {
				$stations = netatmo_lister_stations_dist(
					_request('netatmo_client_id'),
					_request('netatmo_client_secret'),
					_request('netatmo_access_token'),
					_request('netatmo_refresh_token')
				);

				set_request('netatmo_device_mac', $stations);
			} catch (Exception $e) {
				$flux['data']['netatmo_device_mac'] = $e->getMessage();
			}
		}
	}

	return $flux;
}

qui fait appel au fichier de fonctions avec :

function netatmo_authentifier_application_dist(
	string $client_id,
	string $client_secret,
	string $access_token,
	string $refresh_token
): \Netatmo\Clients\NAWSApiClient {
	$config = [
		'client_id' => $client_id,
		'client_secret' => $client_secret,
		'access_token' => $access_token,
		'refresh_token' => $refresh_token,
	];

	$client = new \Netatmo\Clients\NAWSApiClient($config);

	$tokens = $client->getAccessToken();

	$nat = $tokens['access_token'];

	if ($access_token !== $nat) {
		sql_updateq(
			'spip_stations',
			['access_token' => $nat],
			'refresh_token = "' . $refresh_token . '"'
		);
	}

	return $client;
}

function netatmo_lister_stations_dist(
	string $client_id,
	string $client_secret,
	string $access_token,
	string $refresh_token
): array {
	$client = netatmo_authentifier_application_dist($client_id, $client_secret, $access_token, $refresh_token);

	$data = $client->getData();
	$devices = $data['devices'];

	$stations = [];

	foreach ($devices as $device) {
		$stations[$device['_id']] = $device['station_name'];
	}

	return $stations;
}

Ce que je ne veux pas c’est retourner une liste de stations vide si les informations d’authentification sont mauvaises et si l’API me renvoie une erreur.

L’idée serait donc d’afficher un message d’erreur « global » à la manière de SVP, le genre de message qui fait tout trembler. Mais qu’appeler pour cela ?

Bonsoir @b_b et tout le monde,

Après quelques temps passé sur cette histoire, à relire encore et encore la doc formulaire_verifier - Programmer avec SPIP 4, je me rends compte que $flux['data']['unnomdechamp'] = 'mon erreur'; ne fonctionne pas lorsque j’ai le multi-étapes d’activé… Dès que je tente sur un formulaire simple, j’ai bien l’erreur affichée au niveau du champ ciblé.

Vous avez une explication ? Une solution ?

Merci :slight_smile:

@bricebou c’est pas ça qui marche pas, c’est le fait d’utiliser formulaire_truc_verifier() qui ne vaut QUE pour le form complet pas multi étapes.

Pour le multi-étapes c’est formulaires_truc_verifier_1-2-3, OU formulaires_truc_verifier_etape avec le numéro de l’étape dans les args.

Ou encore le pipeline du même nom formulaire_verifier_etape

Au passage le chapitre Vérifier de cette doc

n’est pas complet, puisque ça ne parle NI de la fonction formulaires_inscription_verifier_etape_dist NI du pipeline formulaire_verifier_etape

Et re au passage : je ne vois pas ce que cette doc fait sur spip.net alors qu’il s’agit purement d’un truc de dev, pas d’intégrateurice, donc ça devrait aller sur programmer (et sans doublon).
(Tout comme la doc de déclaration de l’API objets, et la doc d’API editer_liens…)

Merci @rastapopoulos, c’est bien plus clair désormais dans mon esprit ! Mais… le problème est que tel que pensé, je peux avoir plusieurs modules qui ajoutent leurs étapes à eux au formulaire du plugin core avec le pipeline formulaire_saisies ; mais je ne peux évidemment pas avoir deux modules avec la même fonction formulaires_editer_station_verifier_2

Je vais revoir l’architecture globale de la chose je pense, mais lors de mes premiers essais je suis tombé sur l’os de saisies, du multi-étapes et des afficher_si…

Mais tu as lu qu’il y avait une fonction COMMUNE possible, sans en faire pour chaque étape ? Aussi bien en fonction dédiée dist, qu’en pipeline.


RastaPopoulos

Heu… Je crains de ne pas comprendre…

Mais peut-être me suis aussi mal exprimé ou ai-je mal expliqué mon besoin :

  • un plugin core crée l’objet Station et génère un formulaire d’édition de cet objet dans formulaires/editer_station.php ;
  • un plugin « module » aeris vient surcharger ce premier formulaire en ajoutant une étape via la fonction aeris_formulaire_saisies et je dois pouvoir vérifier les informations d’authentification pour aeris fournies à cette étape (la deuxième donc du formulaire d’édition d’une station de type aeris)
  • un plugin « module » netatmo vient aussi surcharger ce formulaire editer_station et lui ajoute deux étapes via netatmo_formulaire_saisies ; la deuxième étape de création d’une station de type netatmo consiste en la saisie de données d’authentification que je dois vérifier avant de passer à la troisième étape qui présente une liste de stations parmi lesquelles il faut en choisir une.

Chaque plugin « module » doit donc procéder à ses propres vérifications à leur étape 2 respective ; et c’est donc là où je ne suis pas sûr de comprendre comment faire…

Bah c’est forcément par le pipeline… puisque c’est des sous-plugins qui s’insèrent dans le CVT d’un plugin parent…

Bon… J’ai fini par comprendre… Mais… Mes modules peuvent ou pas être installés, et en fonction des combinaisons, le nombre d’étapes évolue, et je ne peux m’appuyer sur le numéro d’étape pour réaliser telle ou telle vérification… Il me faudrait en fait les intitulés des étapes, c’est-à-dire les noms des fieldsets…

Plus concrètement :

  • si je n’installe que le module aeris, alors, je dois cibler l’étape 2 ;
  • mais si j’installe le module netatmo puis le module aeris, l’authentification d’une station aeris se retrouve en étape 4…

Je pense à cibler en fonction des champs remplis et des champs encore à saisir… Vous voyez une autre possibilité ?

Un peu foireux, mais peut-être en testant le fait que le module optionel est actif pour faire varier le numéro de l’étape à tester…

Moui, mais je crains de me prendre les pieds dans le tapis parce qu’avec deux modules, ça peut être gérable, mais j’en ai un troisième en réserve… Mais ça soulève une question d’ailleurs, celle de l’ordre d’exécution des pipelines (ceux de netatmo semblent précéder ceux d’aeris, et donc sans doute pas par ordre alphabétique) : par ordre d’activation des plugins ?

`par ordre d’activation des plugins ?

selon l’ordre de dependances. Les plugins qui nécessitent un autre plugins passent après celui là.