Modifica dei valori di un'entità al salvataggio con hook_entity_presave
in un C.T. ho 3 entity reference, in form alter ne valorizzo 2 con i dati presi dal profilo.
$form['field_localita_partenza']['widget']['0']['target_id']['#value'] = DatiUtente('Comune');
e funziona
Il terzo entity reference dopo aver digitato il dato vorrei visualizzarne il contenuto ed ho provato questo codice
echo 'ComuUff '. $form['field_localita_missione']['widget']['0']['target_id']['#value'];
ma mi ritorna errore
Ho visto i vari indici con kint e notato che l'indice #value non esiste. Ho rivisto anche il codice postato da Maurizio Gianovelli
field_codice_funzionario->entity->label();
ma non ho trovato la giusta profondità per poter poter accedere al valore. Mi serve prendere tale valore perchè devo confrontarlo con un altro dato per poer poi valorizzare un checkBox se vero o falso
Risposte
Ho letto degli articoli su
Ho letto degli articoli su $form_state e ho provato questo codice
che mi dovrebbe restituire il valore del campo, ma non mi è chiaro se il getValue si può usare solo in validate o anche in form_alter.
dovrebbe ritornare tutti i valori in un array
In entrambi i casi lo stesso errore di ciò che ho scritto prima
Nei valori post (getValues())
Nei valori post (getValues()) trovi solo l'id (target_id) del campo. Puoi caricare l'entità tramite un metodo load e poi accedere al campo.
Se è un nodo ad esempio e $target_id il valore del campo:
$node = \Drupal\node\Entity::load($target_id);
e poi
$label = $node->label();
Grazie proverò, però mi resta
Grazie proverò, però mi resta l'ignoranza di non aver capito eprchè in form_alter non posso prendere il valore di un campo Data ho notatao che lo stesso è per i campi check
Scusa Maurizio, non sono
Scusa Maurizio, non sono stato chiaro nel secondo post. Il primo è quello che non ho capito. In form alter posso visualizzare i valori dei vari campi, ad eccezione di quelli DateTime ed entity reference, in quanto manca l'indice ['#value'].
La func della validazione del modulo mi funziona e riesco a prendere tutti i campi
La richiesta è motivata dal fatto che in fase di inserimento o modifica del contenuto devo aggiornare dei campi.
Ad esempio ho 2 campi località di tipo entity reference. digito la prima località, digito la seconda e devo aggiornare un checkBox. Se le località sono uguali il check sarà true altrimenti false.
Per quel che ho capito dal validate potrei farlo in quella fase ma ho fatto delle prove ed ho notato che in tale fase non è possibile assegnare un valore ad un campo. L'ho provato col campo title, dove mi serve inserire la data del movimento. Mi ha riportato errore
Puoi cambiare i valori in
Puoi cambiare i valori in fase di validazione con setvalues() (https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormStateInterface.php/function/FormStateInterface%3A%3AsetValue/8.9.x).
Oppure direttamente al salvataggio dell'entità con hook_entity_presave() (https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...).
Proverò il setValue per
Proverò il setValue per mettere il valore data in title ed effettuare il savataggio. In questo C.T. title l'ho nascosto e se non inserisco qualcosa mi ritorna errore. So che c'è un modulo per far ciò ma preferisco imparare programmaticamente come si fa per poter capire meglio drupal.
Relativamente al confronto tra due campi per assegnare il valore ad un altro campo, devo farlo prima del salvataggio. Devo effettuare dei calcoli che saranno diversi a seconda se vero o falso.
Allora l'opzione migliore è
Allora l'opzione migliore è sicuramente sfruttare hook_entity_presave richiamata prima del salvataggio con i dati già tutti disponibili, sia per il valore del titolo sia per il valore condizionale.
Fatto scritto l'hook e
Fatto scritto l'hook e funziona.
Mi resta però il dubbio sul perchè non funzioni questo comando
$form['title']['widget'][0]['value']['#value'] $form['field_data']['widget'][0]['value']['#value'];
Ho provato questo è funziona
$form['title']['widget'][0]['value']['#value'] = "Titolo inserito programmaticamente";
Forse perchè è un campo data?
Sono passato al controllo del
Sono passato al controllo del valore condizionale ma mi sono impantanto
Come prima cosa ho effettuato una prova per far printare il valore del campo condizionale
$a = $form_state->getValues()['field_sede'][0]['value'];
\Drupal::messenger()->addError( $a );
ma mi riporta errore. Ho fatto altre prove ed ho notato che mi visualizza soloi campi testo. e data I campi condizionali e entity reference no.
Ho fatto delle ricerche ma non ho trovato nulla
Mi sa che è lo stesso problema per cui non riesco ad utilizzarlo in form_alter. Nel codice ometto quanlche indice
Posta l'intera
Posta l'intera implementazione del tuo hook_entity_presave. All'interno di questa funzione la variabile form_state non è definita, hai direttamente l'entità completa dei suoi valori prima che i dati vengano salvati nel database.
Scusa ho scritto
Scusa ho scritto un'inesattezza
Di seguito il codice e funziona.
Ho inserito la riga per un primo controllo e va bene.
Anche qui ho notato che il campo entity reference con questo comando non funziona.
Per similitudine ho pensato di usare label() ma non mi ritorna errore
Alla fine il controllo è questo
Controlla quello che ho
Controlla quello che ho scritto qui http://www.drupal.it/supporto/strutturazione-dati#comment-13163, $entity->field_localita_missione->value dovrebbe darti l'id dell'entità referenziata e non l'entità stessa.
Ho letto il commento
Ho letto il commento precedente e letto questo link
https://www.drupal.org/docs/drupal-apis/entity-api/working-with-the-enti...
Che è stato abbastanza illuminante e mi ha fatto capire varie cose.
In questo caso, nel preSave l'entità è riferita al nodo, questo codice
$entity->id()
restituirà l'ID del nodo , provato ed é chiaro, così come la label restituisce il titolo del nodo.
Adesso all'interno del nodo devo prendere i campi che m'interessano. Continuando con l alstessa logica (non ho trovato spiegazioni su come si prende il campo se non dai tuoi esempi)
dovrei scrivere
Entità
nome campo
value per i campi testo o data
per le entity reference
value
id o solo id
nulla mi manca sempre qualcosa per terminare il ragionamento. Vedo se riesco a trovare qualcosa che spiega come costruire la linea di codice in presenza di entity reference o campi condizionali.
Grazie alcune cose adesso mi sono più chiare
Se ti interessa lavorare solo
Se ti interessa lavorare solo sui nodi puoi anche implementare la funzione più specifica hook_node_presave (hook_ENTITY_TYPE_presave). Nota che $entity->id() contiene l'id solo in aggiornamento e non in inserimento. Meglio verificare con $entity->isNew() prima (restituisce vero solo se inserimento).
si avevo letto di isNew ma in
si avevo letto di isNew ma in quest momento è importante che capisca come accedere al valore del campo di riferimento o com id o come label
Rileggi l'intero thread di
Rileggi l'intero thread di http://www.drupal.it/supporto/strutturazione-dati.
Forse sono arrivato alla
Forse sono arrivato alla conclusione dei miei dubbi anche se non mi convince, ho letto vari articoli e visto questo codice, l'ho messo in Pre Save e funziona, ottengo l'id del nodo collegato
Faccio un ragionamento, ti sarei grato se mi indicassi dove sbaglio.
field_localita_rientro - è il nome macchina del campo entity reference - collegato al C.T. Località dove è presente il campo field_distanza
$nid = $entity->get('field_localita_rientro')->getValue()[0]['target_id'];
Adesso dovrei caricare il nodo>$nid per avere accesso ai campi del C.T. collegato e prendere field_distanza
Il codice non mi piace tanto perchè é un misto. Parto dal ragionamento che il campo ha sia il title che il nid nella visualizzazione, significa che ha già i suoi collegamenti pronti
ho proseguito il ragionamento per avere il title
$Loca = $entity->get('field_localita_rientro')->getValue()[0]['target_id']['title'];
ma non va
ho proseguito indicando il nome macchina di un campo
$Dista = $entity->get('field_localita_rientro')->getValue()[0]['target_id']['field_distanza'];
Mi da' i km ma sono sempre riferiti al primo Entity .Reference
Per come sono collegati i campi, almeno come logica, in quanto la mia preparazione è ancora minima dovrebbe essere
$Dista = $entity->field_localita_rientro->entity->field_distanza->value;
Però ho notato che faccio ancora molta confusione tra le proprietà di un oggetto, gli array e le funzioni.
Che ne pensi?
Nei prossimi giorni rileggerò tutto il thread della strutturazione dati
Scusa se sono stato prolisso
Rapido recap per fare
Rapido recap per fare chiarezza, immagina che field_riferimento sia un entity reference a dei nodi (multiplo):
<?php
// restituisce un array di elementi es ['target_id' => 2, 'target_id' => 3]
$retval = $entity->get('field_riferimento')->getValue();
kint($retval);
// alternativa semplificata restituisce un array di elementi es ['target_id' => 2, 'target_id' => 3]
$retval = $entity->field_riferimento->getValue();
kint($retval);
// restituisce un array con il primo elemento es ['target_id' => 2]
$retval = $entity->field_riferimento->get(0)->getValue();
kint($retval);
// restituisce l'id del primo elemento (intero)
$retval = $entity->field_riferimento->get(0)->get('target_id')->getValue();
kint($retval);
// restituisce l'id del secondo elemento (intero)
$retval = $entity->field_riferimento->get(1)->get('target_id')->getValue();
kint($retval);
// alternativa che restituisce l'id del primo elemento (intero)
$retval = $entity->field_riferimento->target_id;
kint($retval);
// alternativa che restituisce l'id del primo elemento (intero)
$retval = $entity->field_riferimento->first()->target_id;
kint($retval);
// alternativa che restituisce l'id del secondo elemento (intero)
$retval = $entity->field_riferimento->get(1)->target_id;
kint($retval);
// restituisce la prima entità es Node con id 2
$retval = $entity->field_riferimento->get(0)->get('entity')->getValue();
kint($retval);
// restituisce la seconda entità es Node con id 3
$retval = $entity->field_riferimento->get(1)->get('entity')->getValue();
kint($retval);
// alternativa precedente per prendere la prima entità
$retval = $entity->field_riferimento->entity;
kint($retval);
// alternativa precedente per prendere la seconda entità
$retval = $entity->field_riferimento->get(1)->entity;
kint($retval);
?>
Più in
Più in generale
$entity->get('field_riferimento')
restituisce un oggetto FieldItemList
$entity->get('field_riferimento')->get(0)
restituisce un oggetto FieldItem
$entity->get('field_riferimento')->get(0)->get('target_id')
restituisce un oggetto TypedData
$entity->get('field_riferimento')->get(0)->get('target_id')->getValue()
restituisce una stringa, un intero, etc...
Grazie per la lezione
Grazie per la lezione Maurizio, attraverso te sto crescendo ed inizio a capirci qualcosa.
Leggerò con molta attenzione quello che hai scritto.
Ad una lettura veloce non capisco il meccanismo dell'entity reference su nodi multipli. Ma sicuramente in seguito mi servirà
Riletto strutturazione dati,
Riletto strutturazione dati, quello che mi serviva già me lo avevi scritto ed io sono stato più di una settimana per capire.
Adesso è più chiaro perchè ci ho sbattuto la testa, devo stare più attento e leggere con calma le tue indicazioni
Ho letto anche l'articolo del link e al più presto proverò a scrivere un modulo personalizzato.
Scusa la domanda quando si scrive un modulo personalizzato bisogna creare una tabella nel database o si può utilizzare la struttura dei campi di un c.t. scritto nell'ide?
se ho capito bene dalla
se ho capito bene dalla lettura di un articolo c'è la funzione statica baseFieldDefinitions che permette di fare ciò
Scusa la domanda quando si
Dipende da quello che ti serve. Inoltre Drupal mette a disposizione altri meccanismi di memorizzazione oltre a quelli citati come State, Tempstore, entità di configurazione ... va tutto valutato in fase di analisi di un progetto in base alle necessità e gli obiettivi.
Con baseFieldDefinitions puoi definire i campi di una tua entità custom. Però il discorso si complica ed è off-topic in questo thread.
Ciao Maurizio, ho proseguito
Ciao Maurizio, ho proseguito facendo varie prove e cercando materiale ma mi stoppo su l tipo di codice da richiamare in base a dove mi trovo.
Il codice che mi hai postato mi è chiaro ma penso possa essere utilizzato su presave e convalida.
Io sto sbattendo ancora la testa su form alter ed il campo entity reference.
Con questo codice in form_alter
riesco a prendere l'id del campo entity reference ma ho notato che funziona unicamente in edit del nodo e non in inserimento
Ho pensato di usare il formObject perchè ho letto che carica tutti i campi della form ed è così.
Lessi che getValue e getValues leggevano i vari campi di un array e quindi dovrebbe andare bene in form_alter ma non ho capito come.
Per campi testo e numerici, mi è chiaro il codice, per il campo chech e entity reference no.
Ho sviscerato gli array con kint ma non ho trovato nulla da poter utilizzare.
Con questo codice
e con la funzione current ho visto che mi ritorna la label del campo. Se l'array è multidimensionale non ho capito qual'è l'indice da utilizzare
Mi potresti dire se quello che serve a me è possibile averlo in form_alter ?
Farò delle prove con onchange
Il valore attuale lo puoi
Il valore attuale lo puoi anche prendere da $form_state->getformObject()->getEntity()->get('field_localita_rientro') ma quello modificato lo hai in fase di submit da $form_state->getValue('field_localita_rientro').
In form_state c'è solo l'id se non sbaglio e se vuoi la label devi caricare l'oggetto e richiamare il metodo label es \Drupal\node\Entity\Node::load($target_id)->label().
Provato e va bene. C'è un
Provato e va bene. C'è un unico problema mi serve avere il valore o il nid del campo entity reference prima dell'invio.
Forse come "prima dell'invio"
Forse come "prima dell'invio" intendi lato client, tramite javascript? O tramite ajax con campi dipendenti / condizionali? In questi casi vedi:
https://www.drupal.org/project/conditional_fields
https://www.drupal.org/project/business_rules (dependent fields)
Scusa, per invio intendo di
Scusa, per invio intendo di avere il dato prima del click sul bottone submit. Dopo aver clikkato sul bottone viene effettuata l'esecuzione della validazione.
Lato client, javascript o ajax è lo stesso. Basta che sia possibile farlo
Io ho la necessità avere il valore di alcuni campi della tabella correlata per prepopolare i campi della form ed effettuare calcoli e alcuni controlli.
Poi dopo aver confermato la form effettuo altri controlli con validate. Mi serve effettuare controlli sia prima che dopo la conferma della form.
Esempio in un content type moviemnti seleziono un'anagrafica (campo entity reference) e dal content type anagrafica (collegata all'entity reference) prendo percentuale ed importo per prepolare i campi della form ed tramite form_alter effettuo dei calcoli prima di confermare il movimento. Se ho capito come funziona drupal.
Ma non ho cpaito ancora come fare a prendere il valore dell'entity reference per poi collegarmi al content type e prendere i valori dei campi che m'interessano
Visto i moduli e business_rules mi potrebbe servire per alcune cose
grazie
Prima del submit, per avere
Prima del submit, per avere un'interazione con l'utente devi usare ajax. Lo scenario descritto comprende più elementi (selezione, ricalcolo etc..). Purtroppo non riesco ad approfondire più di tanto in questa sede, a naso credo che avrai bisogno di studiarti l'utilizzo degli ajax callback dei form (attributo #ajax). Qualcosa che ti possa indirizzare verso una soluzione credo sia questo modulo:
https://www.drupal.org/project/er_auto
Però sicuramente non è una soluzione completa esso stesso.
il modulo è interessante.
il modulo è interessante. Seguirò il consiglio e studierò gli ajax callback
Letti gli articoli sulla
Letti gli articoli sulla funzione di callBack
Ho fatto una semplice prova per capire come funziona ma ho l'impressione che non richiami la funzione in quanto non visualizza il msg
Il campo che richiamo è un entityt reference ma ho provato anche con un campo testo.
Questo il codice in form_alter.
$form['field_localita_missione']['widget'][0]['target_id']['#ajax'] = [
'callback' => 'CercaLocalita',
'event' => 'change',
];
function CercaLocalita($form, FormStateInterface $form_state) {
\Drupal::messenger()->addMessage( 'entrato' );
}
Non ho capito dove sbaglio
ho inserito anche i vari namespace
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\CommandInterface;
Le richieste ajax vengono
Le richieste ajax vengono gestite diversamente da quelle normali. Non puoi aspettarti che con questo codice ti venga restituito un messaggio a schermo perchè solo una porzione di pagina viene eventualmente ricaricata. Leggi meglio tutta la documentazione,
La raccolta di esempi contiene molte informazioni su come usare ajax nei form, studiali e applicali al tuo caso:
https://www.drupal.org/project/examples
noterai che mancano molti elementi al tuo codice per farlo funzionare correttamente. Inoltre inserire i namespaces senza utilizzare gli oggetti in essi contenuti non sortisce alcun effetto (diversamente dagli eventuali Traits). Approfondisci l'argomento e se trovi altre difficoltà (un pò più specifiche di queste) posta una nuova richiesta di supporto.