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 è 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à di nascita (es. "Alfonsine (RA))"')
);
//NAZIONALITA'
$form['main']['nazionalita'] = array(
'#type' => 'textfield',
'#title' => t('Nazionalità'),
'#required' => false,
'#size' => 20,
'#maxlength' => 15,
'#default_value' => isset($node->nazionalita) ? $node->nazionalita : '',
'#description' => t('Inserire la nazionalità (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 è 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à: '.$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.