hook_insert, hook_validate e node_save

2 contenuti / 0 new
Ultimo contenuto
hook_insert, hook_validate e node_save

Ciao a tutti! sto scrivendo un mio modulo per l'inserimento di dati anagrafici per atleti.

ho necessità di fare l'upload di un file, ma ho un problema.

l'oggetto $node invocato nell'hook_validate

function atleti_validate($node, &$form_state)

viene modificato dal metodo in questo modo:

<?php
if (file_copy($file, $destination, FILE_EXISTS_REPLACE))
                   
$node->foto = $file->filepath;
                   
drupal_set_message("L'upload &egrave; andato a buon fine.");
                }
 
?>

e se lancio un PRINT_R immediatamente prima di terminare la function vedo che il campo è presente.

ma nell'hook_insert

function atleti_insert($node)

lanciato immediatamente dopo dal sistema (nella form si presuppone di aver cliccato "Salva"),
$node non contiene più il valore nel campo "foto"...
come posso valorizzare questo campo nel DB? allego il file module completo:

grazie a tutti!

<?php
 
<?php
// $Id: $
/**
 * @file
 * Gestire l'anagrafica degli atleti
 *
 */
/**
 * Implementation of hook_node_info().
 * This is a required node hook. This function describes the nodes provided by
 * this module.
 *
 * The required attributes are:
 * - "name" provides a human readable name for the node,
 * - "module" tells Drupal how the module's functions map to hooks (i.e. if the
 *   module is node_example_foo then node_example_foo_insert will be called
 *   when inserting the node).
 * - "description" provides a brief description of the node type, which is
 *   shown when a user accesses the "Create content" page for that node type.
 *
 * The other optional, attributes:
 * - "has_title" boolean that indicates whether or not this node type has a
 *   title field.
 * - "title_label": the label for the title field of this content type.
 * - "has_body": boolean that indicates whether or not this node type has a
 *   body field.
 * - "body_label": the label for the body field of this content type.
 * - "min_word_count": the minimum number of words for the body field to be
 *   considered valid for this content type.
 */
function atleti_node_info() {
    return array(
   
'atleti' => array(
   
'name' => t('Nuovo atleta'),
   
'module' => 'atleti',
   
'description' => t("Modulo per l'inserimento dell'anagrafica atleti."),
   
'has_title' => false,
   
'title_label' => t('Atleti'),
   
'has_body' => false,
   
'body_label' => t('Corpo atleti'),
    )
    );
}
/**
 * Implementation of hook_access().
 *
 * Node modules may implement node_access() to determine the operations
 * users may perform on nodes. This example uses a very common access pattern.
 */
function atleti_access($op="view_list", $node=null, $account=null) {
   
// drupal_set_message("vengo chiamato.<br />OP: ". print_r($op, true)." <br />NODE: ". print_r($node, true). " <br />ACCOUNT: ". print_r($account, true));
   
if ($op == 'create') {
        return
user_access('crea nuovi', $account);
    }
    if (
$op == 'update') {
        if (
user_access('modifica tutti', $account) || (user_access('modifica propri', $account) && ($account->uid == $node->uid))) {
            return
TRUE;
        }
    }
    if (
$op == 'delete') {
        if (
user_access('elimina tutti', $account) || (user_access('elimina propri', $account) && ($account->uid == $node->uid))) {
            return
TRUE;
        }
    }
    if (
$op == 'view_list') {
        if (
user_access('vedi tutti', $account) || (user_access('vedi propri', $account) && ($account->uid == $node->uid))) {
            return
TRUE;
        }
    }
    return
false;
}
/**
 * Implementation of hook_perm().
 *
 * Since we are limiting the ability to create new nodes to certain users,
 * we need to define what those permissions are here. We also define a permission
 * to allow users to edit the nodes they created.
 */
function atleti_perm() {
    return array(
   
'crea nuovi',
   
'elimina propri',
   
'elimina tutti',
   
'modifica propri',
   
'modifica tutti',
   
'vedi propri',
   
'vedi tutti',
    );
}
function
atleti_menu() {
   
$items = array();
   
$items['atleti/elenco'] = array(
   
'title' => 'Atleti',
   
'description' => 'Descrizione di pagina menu',
   
'page callback' => 'atleti_elenco',
   
'access callback' => 'atleti_access',
   
'access arguments' => array('view_list'),
   
'type' => MENU_NORMAL_ITEM,
    );
    return
$items;
}
/**
 * Funzione per la creazione del listato di tutti gli atleti.
 * Possibilità di
 *
 */
function atleti_elenco(){
   
drupal_add_js('sites/default/scripts/sorttable.js','file');
   
$content = "";
   
$content .= "<div class='elenco'>
    <table class='sortable'>
    <thead>
    <tr>
        <th>ID </th>
        <th>Cognome </th>
        <th>Nome </th>
        <th>Data di nascita </th>
         <th>Categoria </th>
    </tr>
    </thead><tbody>"
;
   
$query = "SELECT * FROM atleti, categorie WHERE atleti.categoria_id = categorie.id ";
   
$res = db_query($query);
    while (
$row = db_fetch_object($res)) {
       
//     print_r($row);
       
$content .= "<tr>
         <td>
$row->id</td>
         <td>
$row->cognome</td>
         <td>
$row->nome</td>
        <td>"
._trasforma_data($row->data_nascita)."</td>
        <td>
$row->categoria</td>
    </tr>"
;
    }
   
$content .="</tbody></table></div>";
    return
$content;
}
/**
*
* Implementazione di hook_form_alter() usato per modificare la form base
*
*/
function atleti_form_alter(&$form, $form_state, $form_id) {
   
//drupal_set_message('<pre>' . print_r($form, TRUE) . '</pre>');
    //drupal_set_message('nome_form: ' . $form_id);
   
if($form_id == 'atleti_node_form') {
       
$form['menu']['#access'] = false;
       
$form['attachments']['#access'] = false;
       
$form['options']['#access'] = false;
       
$form['author']['#access'] = false;
       
$form['comment_settings']['#access'] = false;
       
$form['revision_information']['#access'] = false;
       
$form['path']['#access'] = false;
    }
}
/**
 * Implementation of hook_form().
 *
 * Now it's time to describe the form for collecting the information
 * specific to this node type. This hook requires us to return an array with
 * a sub array containing information for each element in the form.
 */
function atleti_form(&$node, $form_state) {
   
//abilito js e datepicker per la data di nascita
   
jquery_ui_add(array('ui.datepicker'));
   
drupal_add_js(
   
'   $(document).ready(function(){
            $("input#edit-data-nascita").datepicker();
        }
    );
'
,'inline');
   
drupal_add_css("sites/default/modules/jquery_ui/jquery.ui/themes/default/ui.datepicker.css");
   
//devo impostare questo perche' carico un file
   
$form['#attributes'] = array('enctype' => 'multipart/form-data');
   
// The site admin can decide if this node type has a title and body, and how
    // the fields should be labeled. We need to load these settings so we can
    // build the node form correctly.
   
$type = node_get_types('type', $node);
    if (
$type->has_title) {
       
$form['title'] = array(
       
'#type' => 'textfield',
       
'#title' => check_plain($type->title_label),
       
'#required' => TRUE,
       
'#default_value' => $node->title,
       
'#weight' => -5
       
);
    }
    if (
$type->has_body) {
       
// In Drupal 6, we can use node_body_field() to get the body and filter
        // elements. This replaces the old textarea + filter_form() method of
        // setting this up. It will also ensure the teaser splitter gets set up
        // properly.
       
$form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
    }
   
$form['main'] = array(
   
'#type' => 'fieldset',
   
'#title' => check_plain($type->title_label),
   
'#collapsible' => TRUE,
   
'#collapsed' => false,
   
'#tree' => false,
    );
   
// Now we define the form elements specific to our node type.
    //COGNOME
   
$form['main']['cognome'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Cognome'),
   
'#size' => 50,
   
'#maxlength' => 64,
   
'#required' => TRUE,
   
'#default_value' => isset($node->cognome) ? $node->cognome : '',
   
'#description' => t('Cognome atleta')
    );
   
//NOME
   
$form['main']['nome'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Nome'),
   
'#size' => 50,
   
'#maxlength' => 64,
   
'#required' => TRUE,
   
'#default_value' => isset($node->nome) ? $node->nome : '',
   
'#description' => t('Nome atleta')
    );
   
//SESSO
   
$options = array('','M'=>'M','F'=>'F');
   
$form['main']['sesso'] = array(
   
'#type' => 'select',
   
'#required' => false,
   
'#title' => t('Sesso'),
   
'#default_value' => isset($node->sesso) ? $node->sesso : '',
   
'#options' =>  $options,
   
'#description' => t('Selezionare sesso')
    );
   
$options = null;
   
//CATEGORIA
   
$sql = "SELECT `id`, `categoria` FROM `categorie` ORDER BY `id`";
   
$result = db_query($sql);
   
$options = array('');
    while (
$row = db_fetch_array($result)) {
       
$options[$row['id']] = $row['categoria'];
    }
   
$form['main']['categoria_id'] = array(
   
'#type' => 'select',
   
'#title' => t('Categoria'),
   
'#required' => TRUE,
   
'#default_value' => isset($node->categoria_id) ? $node->categoria_id : '',
   
'#options' =>  $options,
   
'#description' => t('Specificare la categoria di appartenenza')
    );
   
$options = null;
   
//ALTEZZA
   
$form['main']['altezza'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Altezza'),
   
'#required' => false,
   
'#size' => '15',
   
'#maxlength' => 3,
   
'#default_value' => isset($node->altezza) ? $node->altezza : '',
   
'#description' => t('Specificare altezza in cm (es. "172")')
    );
   
//PESO
   
$form['main']['peso'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Peso'),
   
'#required' => false,
   
'#size' => '5',
   
'#maxlength' => 3,
   
'#default_value' => isset($node->peso) ? $node->peso : '',
   
'#description' => t('Specificare altezza in Kg')
    );
    if (isset(
$node->data_nascita))
    if (
preg_match(
   
"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$^",
   
$node->data_nascita))
   
$node->data_nascita = _trasforma_data($node->data_nascita);
   
//DATA DI NASCITA
   
$form['main']['data_nascita'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Data di nascita'),
   
'#required' => false,
   
'#size' => 12,
   
'#maxlength' => 10,
   
/*    '#ahah_wrapper' => array(
    'path' => 'sites/default/modules/jquery_ui/jquery.ui/ui/ui.datepicker.js' ,
    'wrapper' => 'Datepicker'
    ),*/
   
'#default_value' => isset($node->data_nascita) ? $node->data_nascita: '',
   
'#description' => t('Inserire data di nascita'),
   
//    'day' => format_date(time(), 'custom', 'j'),
    //   'month' => format_date(time(), 'custom', 'n',0),
    //    'year' => format_date(time(), 'custom', 'Y')
   
);
   
//LUOGO DI NASCITA
   
$form['main']['luogo_nascita'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Luogo di nascita'),
   
'#required' => false,
   
'#size' => 40,
   
'#maxlength' => 60,
   
'#default_value' => isset($node->luogo_nascita) ? $node->luogo_nascita : '',
   
'#description' => t('Inserire la citt&agrave; di nascita (es. "Alfonsine (RA))"')
    );
   
//NAZIONALITA'
   
$form['main']['nazionalita'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Nazionalit&agrave;'),
   
'#required' => false,
   
'#size' => 20,
   
'#maxlength' => 15,
   
'#default_value' => isset($node->nazionalita) ? $node->nazionalita : '',
   
'#description' => t('Inserire la nazionalit&agrave; (es. "ITALIANA")')
    );
   
//CODICE FISCALE
   
$form['main']['cf'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Codice Fiscale'),
   
'#required' => false,
   
'#size' => '20',
   
'#maxlength' => 16,
   
'#default_value' => isset($node->cf) ? $node->cf : '',
   
'#description' => t('Inserire il codice fiscale')
    );
   
//TIPO ISCRIZIONE
   
$options = array('','Provvisoria'=>'Provvisoria','Definitiva'=>'Definitiva');
   
$form['main']['tipo_iscrizione'] = array(
   
'#type' => 'select',
   
'#required' => false,
   
'#title' => t('Tipo di iscrizione'),
   
'#default_value' => isset($node->tipo_iscrizione) ? $node->tipo_iscrizione : '',
   
'#options' =>  $options,
   
'#description' => t('Specificare il tipo di iscrizione')
    );
   
$options = null;
   
//FOTO
    //se ho fatto "Anteprima" la foto è già stata inviata. quindi la mostro
    //metto doppio controllo per sicurezza (ma è uguale in teoria)
   
if ($node->op == "Anteprima"){
       
drupal_set_message("foto: ".$node->foto);
        ;
//if ($node->foto)
   
}
   
$form['main']['foto'] = array(
   
'#type' => 'file',
   
'#title' => t('Foto'),
   
'#size' => 80,
   
//'#default_value' => isset($node->foto) ? $node->foto : '',
   
'#description' => t('Seleziona la foto per l\'upload')
    );
   
//NOTE
   
$form['main']['note'] = array(
   
'#type' => 'textarea',
   
'#required' => false,
   
'#title' => t('Note aggiuntive'),
   
'#default_value' =>  isset($node->note) ? $node->note : '',
   
'#cols' => 60,
   
'#rows' => 5,
   
'#description' => t('Campo per eventuali informazioni addizionali'),
    );
   
/* //PULSANTE SUBMIT
    $form['submit'] = array (
    '#type' => 'submit',
    '#value' => t('Invia'),
    );
    //PULSANTE RESET
    $form['reset'] = array (
    '#type' => 'button',
    '#value' => t('Cancella'),
    );
    $form['#validate'][] = 'atleti_validate';
    $form['#submit'][] = 'atleti_submit';
    */
   
return $form;
}
/**
 * Implementation of hook_validate().
 *
 * Our "quantity" field requires a number to be entered. This hook lets
 * us ensure that the user entered an appropriate value before we try
 * inserting anything into the database.
 *
 * Errors should be signaled with form_set_error().
 */
function atleti_validate($node, &$form_state) {
   
//drupal_set_message( "questo e' il validate <pre>" . print_r($form_state, true)."</pre>");
    //ALTEZZA
    //controllo che l'altezza sia un numero e >0
   
if ($node->altezza != '' && !(is_numeric($node->altezza) && $node->altezza >0)){
       
form_set_error('altezza', t('Errore ALTEZZA deve essere numerico e maggiore di zero.'));
    }
   
//PESO
    //controllo che peso sia un numero e >0
   
if ($node->peso != '' && !(is_numeric($node->peso) && $node->peso >0)){
       
form_set_error('peso', t('Errore PESO deve essere numerico e maggiore di zero.'));
    }
   
//DATA DI NASCITA
    //controllo che sia antecedente ad oggi //TODO
    //CONTROLLO SUL CODICE FISCALE
   
if ($node->cf != '' && strlen($node->cf) != 16){
       
form_set_error('cf', t('Errore CODICE FISCALE deve essere lungo 16 caratteri.'));
    }
   
$errors_in_form = is_array(form_get_errors());
   
//CONTROLLO FOTO
    //se il file ha nome = '' allora non ho caricato la foto.evito i controlli
   
if (!$errors_in_form && $_FILES['files']['name']['foto'] != ''){
       
// mi ha dato errori nell'array $_FILES?
       
if ($_FILES['files']['error']['foto'] == '0'){
           
//esiste il file temp?
            // if (!file_exists($_FILES['files']['tmp_name']['foto']))
            //     form_set_error('foto', t('File non caricato. Errore.'));
            //salvo il file uploadato dentro la cartella immagini, in un direttorio che si chiami come
            //il nome del modulo. così mantengo un po' di ordine! (altrimenti mi sparo...)
            //TODO: rimpiazzare il nome "atleti" con una variabile che contenga il nome del modulo
           
$validators = array('file_validate_is_image' => array(),
           
'file_validate_image_resolution' => array('1024x768'),
           
'file_validate_size' => array(2000000),
            );
            if (
$file = file_save_upload('foto',$validators)){
               
$info = image_get_info($file->filepath);
               
//nome: immagini/atleti/atl_TUFANO_02.jpg
               
$dir = 'immagini/atleti';
               
$destination = $dir."/atl_".$node->cognome."_".$node->categoria_id.".".$info['extension'];
                if (
file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
                  
// $form_state['values']['foto'] = $file->filepath;
                   
$node->foto = $file->filepath;
                   
drupal_set_message("L'upload &egrave; andato a buon fine.");
                }
                else {
                   
form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.",
                    array(
'%directory' => $destination)));
                }
            }
            else
form_set_error("Errore nell'upload");
        }
    }
   
node_save($node);
}
/**
 * Implementation of hook_insert().
 *
 * As a new node is being inserted into the database, we need to do our own
 * database inserts.
 */
function atleti_insert($node) {
   
db_query("INSERT INTO atleti
  (vid, nid, cognome, nome, sesso, categoria_id, altezza, peso, data_nascita, luogo_nascita,
  nazionalita,cf,tipo_iscrizione,foto,note)
  VALUES
  (%d, %d, '%s', '%s','%s',%d,%d,%d,'%s','%s','%s','%s','%s','%s','%s')"
,
   
$node->vid, $node->nid, strtoupper($node->cognome), strtoupper($node->nome),$node->sesso,$node->categoria_id,$node->altezza,
   
$node->peso,_trasforma_data($node->data_nascita,"TO_DB"),$node->luogo_nascita,
   
strtoupper($node->nazionalita),strtoupper($node->cf),$node->tipo_iscrizione,$node->foto,$node->note);
   
drupal_set_message("insert done (per davvero!).");
}
/**
 * Implementation of hook_update().
 *
 * As an existing node is being updated in the database, we need to do our own
 * database updates.
 */
function atleti_update($node) {
   
// if this is a new node or we're adding a new revision,
   
if ($node->revision) {
       
drupal_set_message("update della revision.");
       
atleti_insert($node);
    }
    else {
       
db_query("UPDATE atleti
SET
cognome = '%s', nome = '%s', sesso = '%s', categoria_id = %d, altezza = %d, peso = %d,
data_nascita = '%s', luogo_nascita = '%s',nazionalita = '%s',cf = '%s',tipo_iscrizione = '%s',
foto = '%s',note = '%s'
WHERE
vid = %d"
, strtoupper($node->cognome), strtoupper($node->nome),$node->sesso,$node->categoria_id,$node->altezza,
       
$node->peso,_trasforma_data($node->data_nascita,"FROM_DB"),$node->luogo_nascita,strtoupper($node->nazionalita),strtoupper($node->cf),
       
$node->tipo_iscrizione,$node->foto,$node->note, $node->vid);
       
drupal_set_message("update done (per davvero!).");
    }
}
/**
 * Implementation of hook_nodeapi().
 *
 * When a node revision is deleted, we need to remove the corresponding record
 * from our table. The only way to handle revision deletion is by implementing
 * hook_nodeapi().
 */
/*function atleti_nodeapi(&$node, $op, $teaser, $page) {
    echo "<br><br><br>dentro nodeapi <br>$op<br><br><br>";
            print_r($node);
    switch ($op) {
        case "Salva":
            echo "<br><br><br>dentro nodeapi <br><br>";
            print_r($node);
            break;
        case 'delete revision':
            // Notice that we're matching a single revision based on the node's vid.
            // db_query('DELETE FROM {node_example} WHERE vid = %d', $node->vid);
            drupal_set_message("delete revision done (per finta).");
            break;
    }
}*/
/**
 * Implementation of hook_delete().
 *
 * When a node is deleted, we need to remove all related records from our table.
 */
function atleti_delete($node) {
   
// Notice that we're matching all revision, by using the node's nid.
    //db_query('DELETE FROM {node_example} WHERE nid = %d', $node->nid);
    //devo cancellare anche dalla tabella NODE (o forse lo fa in automatico?)
   
drupal_set_message("delete done (per finta).");
}
/**
 * Implementation of hook_load().
 *
 * Now that we've defined how to manage the node data in the database, we
 * need to tell Drupal how to get the node back out. This hook is called
 * every time a node is loaded, and allows us to do some loading of our own.
 */
function atleti_load($node) {
   
$additions = db_fetch_object(db_query('SELECT * FROM atleti WHERE vid = %d', $node->vid));
   
drupal_set_message("load done (per davvero!). Il node contiene ". print_r($node, true));
    return
$additions;
}
/**
 * Implementation of hook_view().
 *
 * This is a typical implementation that simply runs the node text through
 * the output filters.
 */
function atleti_view($node, $teaser = FALSE, $page = FALSE) {
   
$node = node_prepare($node, $teaser);
   
$node->content['myfield'] = array(
   
'#value' => theme('atleti_elenco', $node),
   
'#weight' => 1,
    );
    return
$node;
}
/**
 * Implementation of hook_theme().
 *
 * This lets us tell Drupal about our theme functions and their arguments.
 */
function atleti_theme() {
    return array(
   
'atleti_vista_singola' => array('arguments' => array('node'),),
   
'atleti_elenco'        => array('arguments' => array(),),
    );
}
function
theme_atleti_elenco(){
    return
"elenco";
}
/**
 * A custom theme function.
 *
 * By using this function to format our node-specific information, themes
 * can override this presentation if they wish. We also wrap the default
 * presentation in a CSS class that is prefixed by the module name. This
 * way, style sheets can modify the output without requiring theme code.
 */
function theme_atleti_vista_singola($node) {
   
$cat = db_fetch_object(db_query('SELECT * from categorie where categorie.id = %d'$node->categoria_id));
   
drupal_set_message("list: Il node contiene ". print_r($node, true));
   
$output = '<div class="main_frame_atleti">';
   
$output = '<div class="foto_atleti">
  Categoria: '
.$cat->categoria.'
  <br />Societ&agrave;: '
.$cat->societa.' </div>';
   
$output .= t('Atleta: '. $node->cognome.", ". $node->nome);
   
$output .= '</div>';
    return
$output;
}
/**
 * Funzione che si occupa di gestire la conversione del campo data dal DB alla scheda e viceversa.
 *
 * @param $data la data da convertire
 * @param $direction può essere "FROM_DB" (default", o "TO_DB". indica se stiamo prendendo il dato dal DB (FROM) o se abbiamo intenzione di scriverlo nel db (TO)
 * @return la stringa convertita
 */
function _trasforma_data($data, $direction = "FROM_DB"){
   
// drupal_set_message("tras_da: ". $data);
   
switch ($direction){
        case
'FROM_DB':
           
$d = explode("-",$data);
            return
"{$d[2]}/{$d[1]}/{$d[0]}";
        case
'TO_DB':
           
$d = explode("/", $data);
            return
"{$d[2]}-{$d[1]}-{$d[0]}";
        default: return
'9999-99-99';
    }
}
 
?>

Il problema è che hook_validate non permette la (permanente) modifica di $node. Infatti la validazione serve semplicemente per dire se il form ha errori.

Forse devi usare hook_nodeapi testando per $op == 'insert' e 'update'. Poi se usi questo hook puoi mettere il codice di validazione proprio li dentro.

Nel $node (questa volta modificabile perchè c'è la & prima del parametro) troverai anche gli elementi del form - vedi taxonomy.module per un esempio.

Più imparo, più dubito.