Ich füge mit field_attach_form () bestimmte Felder aus einem Inhaltstyp in ein benutzerdefiniertes Formular ein. Wenn das Formular gesendet wird, verarbeite ich diese Felder, indem ich field_attach_form_validate () und field_attach_submit () von #validate- und #submit-Rückrufen aufrufe.
Zu diesem Zeitpunkt möchte ich das vorbereitete Node-Objekt nach dem Senden mit dem ursprünglichen Node vergleichen und mich nur mit node_save () befassen, wenn sich eines der Felder geändert hat. Daher beginne ich mit dem Laden des ursprünglichen Knotens mit entity_load_unchanged()
.
Leider stimmen die Feldarrays im ursprünglichen Knotenobjekt nicht mit den Feldarrays im vorbereiteten Knotenobjekt überein, das darauf wartet, gespeichert zu werden, auch wenn keine Änderungen an den Feldern vorgenommen wurden, also ein einfaches "$ old_field == $ new_field" "vergleich ist unmöglich. Zum Beispiel erscheint ein einfaches Textfeld im Original so:
$old_node->field_text['und'][0] = array(
'value' => 'Test',
'format' => NULL,
'safe_value' => 'Test',
);
Während es im vorbereiteten Knoten so aussieht.
$node->field_text['und'][0] = array(
'value' => 'Test',
);
Sie könnten denken, nur den 'Wert'-Schlüssel zu vergleichen, aber dann stoßen Sie auf Felder, die aus anderen Elementen bestehen, die keine' Wert'-Schlüssel haben. Schauen wir uns zum Beispiel ein Adressfeld an, in dem es keinen "Wert" -Schlüssel gibt und Schlüssel sowohl im alten als auch im vorbereiteten Knoten vorhanden sind, die keine Gegenstücke haben.
Alter Knoten
$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,
);
Vorbereiteter Knoten
$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',
);
Bei leeren Feldern gibt es noch eine Diskrepanz.
Alter Knoten
$old_node->field_text = array();
Vorbereiteter Knoten
$node->field_text = array(
'und' => array(),
);
Kann ich den alten und den neuen Wert eines Feldes generisch vergleichen, um festzustellen, ob es sich geändert hat oder nicht?
Ist das nur eine Unmöglichkeit?
_field_invoke()
oder etwas im Zusammenhang mit der Vorbereitung der vollständigen Feldstruktur vom "vorbereiteten" Knoten, dem Rendern beider Felder und dem einfachen Vergleichen dieser HTML-Zeichenfolgen. Nur eine Idee.Antworten:
Dies sollte endlich als allgemeine Lösung funktionieren. Vielen Dank an Clive und morbiD für alle Eingaben.
Übergeben Sie beide Versionen des Knotens an die folgende Funktion. Es wird:
Ziehen Sie alle bearbeitbaren Felder des erkannten Inhaltstyps und ihre bearbeitbaren Spalten (dh Elemente, die möglicherweise im benutzerdefinierten Formular angezeigt werden) in einer einzigen Abfrage aus der Datenbank.
Ignorieren Sie Felder und Spalten, die in beiden Versionen vollständig leer sind.
Behandeln Sie ein Feld, das zwischen den beiden Versionen eine unterschiedliche Anzahl von Werten aufweist, als Änderung.
Durchlaufen Sie jedes Feld, jeden Wert und jede Spalte und vergleichen Sie die beiden Versionen.
Vergleichen Sie Elemente nicht identisch (! =), Wenn sie numerisch sind, und identisch (! ==), wenn es sich um etwas anderes handelt.
Geben Sie bei der ersten erkannten Änderung sofort TRUE zurück (da eine Änderung ausreicht, um zu wissen, dass der Knoten erneut gespeichert werden muss).
Gibt FALSE zurück, wenn nach dem Vergleich aller Werte keine Änderung festgestellt wird.
Vergleichen Sie Feldsammlungen rekursiv, indem Sie sie und ihr Schema laden und die Ergebnisse an sich selbst übergeben. Dies SOLLTE sogar erlauben, verschachtelte Feldsammlungen zu vergleichen. Der Code sollte KEINE Abhängigkeit vom Field Collection-Modul haben.
Lassen Sie mich wissen, wenn dieser Code weitere Fehler oder Tippfehler enthält.
Manchmal interessiert es Sie, welche Felder sich geändert haben. Um das zu wissen, können Sie diese Version der Funktion verwenden:
Manchmal möchten Sie möglicherweise festlegen, dass das Ändern bestimmter Felder eines Knotens nicht dazu führt, dass der "geänderte" Zeitstempel dieses Knotens aktualisiert wird. Dies könnte folgendermaßen implementiert werden:
BEARBEITEN (30.07.2013) Die Unterstützung für Feldsammlungen wurde verbessert . Unterstützung für Felder mit mehreren Werten hinzugefügt.
EDIT (31.07.2015) Neue Version der Funktion, die zurückgibt, welche Felder geändert wurden, und Beispielanwendungsfall.
quelle
Hier ist ein anderer, einfacherer Ansatz, der die komplexen Vergleiche der serverseitigen Werte vermeidet und mit jeder Form funktioniert:
Sie können ein Plugin für fehlerhafte jQuery-Formulare verwenden, z. B. https://github.com/codedance/jquery.AreYouSure
Andere, mit denen Sie sich den Status "Geändert / Dirty" anhören können, funktionieren jedoch auch.
Fügen Sie einen Listener hinzu, um den Wert eines ausgeblendeten Formularelements festzulegen:
Setzen Sie das ausgeblendete Formularelement auf den Standardwert "geändert", um es standardmäßig für Benutzer mit deaktiviertem Javascript zu speichern (~ 2%).
z.B:
Sie können dann den Wert des ausgeblendeten Elements überprüfen
if ($form_state['values']['hidden_indicator'] == 'changed') { /* node_save($node) */ }
Validieren / Übermitteln Sie die Handler in Ihrem Formular.
quelle
Drupal.behaviors.formUpdated
möglicherweiseval()
damit verknüpft sein könnte, obwohl es so aussieht, als würde es ausgelöst, ohne dass sich der Wert tatsächlich ändert (z. B. Klickereignis), während die dedizierten Plug-ins tatsächlich geänderte Formularwerte besser erkennen können.Ich bin mir nicht sicher, ob das perfekt ist, aber warum nicht umgekehrt, indem ich die Formulare anstelle der Knotenobjekte vergleiche ?
Ich bin mir nicht sicher, ob Sie sich strikt in einem Knotenformular befinden, aber Sie können das Formular trotzdem mit Ihrem alten Knoten und Ihrem neuen Knoten rendern:
Vergleichen Sie Ihre Formulare ...
Ich hoffe, es ist eine gute Strecke ... lass es mich wissen.
quelle
Hier ist eine Methode mit hook_node_presave ($ node). Es ist nur ein Modell, wenn Sie denken, dass es hilft, testen Sie es und verbessern Sie es auf Ihre Bedürfnisse!
Ich nehme an, dass für jeden Feldwert die in $ node definierten Instanzen definiert und in $ node_before gleich sein müssen. Ich kümmere mich nicht um die Felder des Feldwerts, die sich in $ node_before und nicht in $ node befinden. Ich nehme an, sie bleiben gleich.
quelle
Dies ist nur ein Code, den ich zusammengeschustert habe. Der gesamte Kredit muss an @eclecto gehen, um die gesamte Beinarbeit zu erledigen. Dies ist nur eine (ebenfalls nicht getestete) Variante, die die Knotenobjekte direkt aufnimmt, die DB-Treffer ein wenig reduziert und die Sprachaushandlung übernimmt.
quelle
Die Antwort ist großartig und hat mir geholfen, aber es gibt etwas, das ich korrigieren musste.
In der
foreach()
Schleife, musste ich von ändern$new_field
zu$old_field
. Ich weiß nicht, ob es sich um eine neue Version von Drupal oder nur um meinen Code handelt (möglicherweise aufgrund eines anderen Codes an einer anderen Stelle), aber ich habe keinen Zugriff auf$new_field['entity']
.quelle
Danke für den Beitrag, hat mir echt viel Zeit gespart. Ich habe eine Reihe von Warnungen und Hinweisen behoben, die von der Funktion ausgegeben wurden:
quelle