J'ajoute certains champs d'un type de contenu dans un formulaire personnalisé en utilisant field_attach_form (). Lorsque le formulaire est soumis, je traite ces champs en appelant field_attach_form_validate () et field_attach_submit () à partir des rappels #validate et #submit.
À ce stade, je veux comparer l'objet de nœud préparé post-soumission au nœud d'origine et ne le dérange que pour node_save () si l'un des champs a changé. Par conséquent, je commence par charger le nœud d'origine à l'aide de entity_load_unchanged()
.
Malheureusement, les tableaux de champs dans l'objet nœud d'origine ne correspondent pas aux tableaux de champs dans l'objet nœud préparé qui attend d'être enregistré, même si aucune modification n'a été apportée aux champs, donc un simple "$ old_field == $ new_field "la comparaison est impossible. Par exemple, un simple champ de texte apparaît comme ceci dans l'original:
$old_node->field_text['und'][0] = array(
'value' => 'Test',
'format' => NULL,
'safe_value' => 'Test',
);
Alors que dans le nœud préparé, cela apparaît comme ceci.
$node->field_text['und'][0] = array(
'value' => 'Test',
);
Vous pourriez penser à comparer simplement la clé «valeur», mais vous rencontrez ensuite des champs composés d'autres éléments qui n'ont pas de clé «valeur». Par exemple, regardons un champ d'adresse où il n'y a pas de clé «valeur» et il y a des clés dans les nœuds anciens et préparés qui n'ont pas d'homologues.
Ancien noeud
$old_node->field_address['und'][0] = array(
'country' => 'GB',
'administrative_area' => 'Test',
'sub_administrative_area' => NULL,
'locality' => 'Test',
'dependent_locality' => NULL,
'postal_code' => 'Test',
'thoroughfare' => 'Test',
'premise' => 'Test',
'sub_premise' => NULL,
'organisation_name' => 'Test',
'name_line' => 'Test',
'first_name' => NULL,
'last_name' => NULL,
'data' => NULL,
);
Noeud préparé
$node->field_address['und'][0] = array(
'element_key' => 'node|page|field_address|und|0',
'thoroughfare' => 'Test',
'premise' => 'Test',
'locality' => 'Test',
'administrative_area' => 'Test',
'postal_code' => 'Test',
'country' => 'GB',
'organisation_name' => 'Test',
'name_line' => 'Test',
);
Pour les champs vides, il existe encore un autre écart.
Ancien noeud
$old_node->field_text = array();
Noeud préparé
$node->field_text = array(
'und' => array(),
);
Puis-je comparer de manière générique l'ancienne et la nouvelle valeur d'un champ pour détecter s'il a changé ou non?
Est-ce juste une impossibilité?
_field_invoke()
ou quelque chose de similaire pour préparer la structure complète des champs à partir du nœud "préparé", rendre les deux champs et simplement comparer ces chaînes HTML. Juste une idée.Réponses:
Cela devrait enfin fonctionner comme une solution générique. Merci à Clive et morbiD pour toutes les contributions.
Passez les deux versions du nœud à la fonction suivante. Ce sera:
Tirez tous les champs modifiables du type de contenu détecté et leurs colonnes modifiables (c'est-à-dire les éléments qui pourraient éventuellement apparaître sur le formulaire personnalisé) de la base de données dans une seule requête.
Ignorez les champs et les colonnes qui sont complètement vides dans les deux versions.
Traitez un champ qui a un nombre différent de valeurs entre les deux versions comme une modification.
Parcourez chaque champ, valeur et colonne et comparez les deux versions.
Comparez les éléments de manière non identique (! =) S'ils sont numériques et identiquement (! ==) s'ils sont autre chose.
Renvoyez immédiatement TRUE lors du premier changement qu'il détecte (puisqu'un changement suffit pour savoir que nous devons réenregistrer le nœud).
Retourne FALSE si aucun changement n'est détecté après que toutes les valeurs ont été comparées.
Comparez récursivement les collections de champs en les chargeant et leur schéma et en transmettant les résultats à lui-même. Cela DEVRAIT même lui permettre de comparer les collections de champs imbriqués. Le code ne doit PAS avoir de dépendance sur le module Field Collection.
Faites-moi savoir s'il y a plus de bogues ou de fautes de frappe dans ce code.
Parfois, vous souhaitez savoir quels champs ont changé. Pour le savoir, vous pouvez utiliser cette version de la fonction:
Parfois, vous souhaiterez peut-être faire en sorte que la modification de certains champs d'un nœud n'entraîne pas la mise à jour de l'horodatage "modifié" de ce nœud. Cela pourrait être mis en œuvre comme suit:
EDIT (7/30/2013) Renforcement du support de collecte sur le terrain. Ajout de la prise en charge des champs avec plusieurs valeurs.
EDIT (31/07/2015) Version ajoutée de la fonction qui retourne quels champs ont changé et exemple d'utilisation.
la source
Voici une autre approche, plus simple, qui évite les comparaisons de valeurs côté serveur complexes et fonctionnerait avec n'importe quelle forme:
Vous pouvez utiliser un plugin de formulaire sale jQuery tel que https://github.com/codedance/jquery.AreYouSure
Bien que d'autres qui vous permettent d'écouter le formulaire modifié / statut sale fonctionneraient également.
Ajoutez un écouteur pour définir la valeur d'un élément de formulaire masqué:
Définissez l'élément de formulaire masqué sur une valeur par défaut «modifié» pour enregistrer par défaut pour les utilisateurs avec Javascript désactivé (~ 2%).
par exemple:
Vous pouvez ensuite vérifier la valeur de l'élément caché
if ($form_state['values']['hidden_indicator'] == 'changed') { /* node_save($node) */ }
dans votre formulaire, validez / soumettez les gestionnaires.
la source
Drupal.behaviors.formUpdated
peut-être leval()
pourrait être liée à cela, même s'il semble qu'elle se déclenchera sans que la valeur ne change réellement (par exemple, inclut l'événement de clic), tandis que les plugins dédiés sont mieux à même de détecter les valeurs de formulaire modifiées.Je ne suis pas sûr que ce soit parfait, mais pourquoi ne pas le prendre dans l'autre sens, en comparant les formes au lieu des objets nœuds ?
Je ne suis pas sûr que vous soyez si vous êtes strictement dans une forme de nœud, mais de toute façon vous pouvez rendre le formulaire avec votre ancien nœud et votre nouveau nœud:
Comparez vos formulaires ...
J'espère que c'est une bonne piste ... faites le moi savoir.
la source
Voici une méthode utilisant hook_node_presave ($ node). Ce n'est qu'une maquette, si vous pensez que cela aide, testez-la et améliorez-la selon vos besoins!
Je suppose que, pour chaque valeur de champ, les instances définies dans $ node doivent être définies et égales dans $ node_before. Je ne me soucie pas des champs de valeur de champ qui sont dans $ node_before et ne sont pas dans $ node, je suppose qu'ils restent les mêmes.
la source
Ce n'est qu'un code que j'ai bricolé. Tout crédit doit aller à @eclecto pour avoir fait tout le travail des jambes. Il s'agit simplement d'une variante (similaire non testée) qui prend directement les objets du nœud, réduit un peu les hits de la base de données et s'occupe de la négociation du langage.
la source
La réponse fournie est excellente et cela m'a aidé, mais il y a quelque chose que j'ai dû corriger.
Dans la
foreach()
boucle, j'ai dû changer de$new_field
à$old_field
. Je ne sais pas s'il s'agit d'une nouvelle version de Drupal ou seulement de mon code (peut-être dû à un autre code ailleurs), mais je n'y ai pas accès$new_field['entity']
.la source
Merci pour le message, ça m'a vraiment fait gagner beaucoup de temps. J'ai corrigé un tas d'avertissements et d'avis que la fonction sortait:
la source