Integrare un modulo con views

 
Esempio di vista generata dall'integrazione del nostro modulo con views
  1. Alzi la mano chi non ha mai usato views.
  2. Alzi la mano che l'ha mai usato.

Ok, non proprio tutti ma buona parte di voi ha alzato la mano, questo perchè è sicuramente uno strumento potentissimo per la visualizzazione delle informazioni, quindi è fondamentale (o comunque molto utile) andare ad integrare i propri moduli con views, permettendo così la massima facilità di utilizzo successiva.

Vediamo ora come andare ad integrare delle tabelle del nostro modulo in modo che siano collegate a views.

Iniziamo creando un modulo che si occupa di salvare dei dati su delle tabelle aggiuntive. Nel caso specifico aggiunge a tutti i nodi un campo checkbox che indica la disponibilità di quell'elemento (per noi ogni nodo sarà un prodotto) e il codice dell'articolo rappresentato da quel nodo.

Per fare questo andiamo a scomodare i classici hook_form_alter() e hook_nodeapi(), non vi annoierò andando a spiegare nei minimi dettagli questa parte, ma vediamo a grandi linee il codice:

<?php
/**
* Implementation of hook_form_alter().
*/
function viewsintegration_form_alter(&$form, $form_state, $form_id) {
  if (
$form_id == 'node_type_form' && isset($form['identity']['type'])) {
   
// Add configuration here
 
}
  elseif (isset(
$form['type']) && isset($form['#node'])) {
    if (
$form['type']['#value'] .'_node_form' == $form_id) {
     
$node = $form['#node'];
     
     
$form['datainfo'] = array(
       
'#type'          => 'fieldset',
       
'#title'         => t('Informazioni varie'),
       
'#description'   => t("Informazioni varie, inserite come prova per l'integrazione con views"),
       
'#weight'        => -2,
       
'#collapsible'   => true,
       
'#collapsed'     => false,
      );
     
     
$form['datainfo']['aviable'] = array(
       
'#type'          => 'checkbox',
       
'#title'         => t('Disponibile'),
       
'#description'   => t('Setta la disponibilità di questo prodotto'),
       
'#required'      => TRUE,
       
'#default_value' => $node->aviable,
      );
     
     
$form['datainfo']['code'] = array(
       
'#type'          => 'textfield',
       
'#title'         => t('Codice del prodotto'),
       
'#description'   => t('Permette di impostare il codice di questo prodotto'),
       
'#required'      => true,
       
'#default_value' => $node->code,
       
'#maxlength'     => 32,
      );
    }
  }
}
?>

Con questo pezzo di codice aggiungiamo un elemento collassabile ai form dei nodi e andiamo a metterci all'interno il checkbox e un campo testo per l'inserimento del codice del prodotto.

La parte successiva riguarda la gestione delle informazioni inserite, operazione che può essere effettuata per le operazioni di inseritmento, cancellazione, aggiornamento, caricamento e visualizzazione. Sarebbe possibile andare a fare ulteriori controlli (come la validazione), ma ora non è il punto che ci interessa, quindi bypassiamo questo passaggio.

<?php
/**
* Implementation of hook_nodeapi().
*/
function viewsintegration_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch (
$op) {
    case
'delete':
     
$results = db_query("DELETE FROM {viewsintegration} WHERE nid = %d", $node->nid);
      break;
    case
'insert':
     
$obj = new stdClass();
     
     
$obj->aviable = $node->aviable;
     
$obj->code    = $node->code;
     
$obj->nid     = $node->nid;
     
     
drupal_write_record('viewsintegration', $obj);
      break;
    case
'load':
     
$data = db_fetch_object(db_query("SELECT * FROM {viewsintegration} WHERE nid = %d", $node->nid));
     
     
$node->aviable = $data->aviable;
     
$node->code    = $data->code;
      break;
    case
'update':
     
$obj = new stdClass();
     
     
$obj->aviable = $node->aviable;
     
$obj->code    = $node->code;
     
$obj->nid     = $node->nid;
     
     
drupal_write_record('viewsintegration', $obj, array('nid'));
      if(!
db_affected_rows()) {
       
drupal_write_record('viewsintegration', $obj);
      }
      break;
    case
'view':
       
$node = node_prepare($node, $teaser);
       
       
$header = array(t('Disponibile'), t('Codice'));
       
$rows[] = array(
         
$node->aviable ? t('Sì') : t('No'),
         
$node->code
       
);
       
       
$node->content['viewsintegration'] = array(
         
'#value'  => theme('table', $header, $rows),
         
'#weight' => -2,
        );
       
        return
$node;
      break;
  }
}
?>

Ovviamente le informazioni devono essere inserite su di una tabelal del database creata in fase di installazione, anche in questo caso date un occhiata al file install che trovate nel modulo di esempio allegato che vedere come vieen generata, ma vediamo velocemente come è strutturata questa tabella:

tabella:
  {viewsintegration}
campi:
  nid (INT, chiave primaria)
  aviable (INT)
  code (VARCHAR, 32 elementi)

Il primo elemento, l'nid che è anche la chiave primaria, serve a mantenere la relazione tra i dati inseriti e il nodo associato (campo nid della tabella nodes).

L'integrazione con views

Come prima cosa dobbiamo andare ad inserire la chiamata all'hook_views_api() che indica a quale versione delle api di views ci stiamo riferendo, nel nostro caso parliamo della versione 2, quindi avremo:

<?php
/**
* Implementation of hook_views_api.
*/
function viewsintegration_views_api() {
  return array(
'api' => 2);
}
?>

In questo modo il sistema saprà che il tutto è collegato al modulo views versione 2.

Il secondo passaggio è l'inserimento della chiamata all'hook_views_data() che invece si occupa di spiegare come il nostro modulo si collega a views, quali informazioni fornisce, .... Vediamo ora il codice e di seguito cosa significa:

<?php
/**
* Implementation of hook_views_data()
*/
function viewsintegration_views_data() {
 
// ======================================================================
  // Generic info
 
$data['viewsintegration']['table']['group']  = t('Views integration');

  $data['viewsintegration']['table']['base'] = array(
   
'field'  => 'nid', // Primary key of table
   
'title'  => t('Views integration'),
   
'help'   => t("Tabella di esempio per l'integrazione con views"),
   
'weight' => -10,
  );
 
 
// ======================================================================
  // Table join
 
$data['node']['table']['join'] = array(
   
'viewsintegration' => array(
     
'left_field' => 'nid',
     
'field'      => 'nid',
    ),
  );
 
 
// ======================================================================
  // Fields  of table
 
$data['viewsintegration']['aviable'] = array(
   
'title'  => t('Disponibilità'),
   
'help'   => t('Disponibilità del prodotto'),
   
   
'field'  => array(
     
'handler'        => 'views_handler_field_boolean',
     
'click sortable' => TRUE,
    ),
   
// Information for accepting a name as a filter
   
'filter' => array(
     
'handler'        => 'views_handler_filter_boolean_operator',
    ),
  );
 
 
// Fields  of table
 
$data['viewsintegration']['code'] = array(
   
'title'  => t('codice'),
   
'help'   => t('codice del prodotto'),
   
   
'field'  => array(
     
'handler'        => 'views_handler_field',
     
'click sortable' => TRUE,
    ),
   
// Information for accepting a name as a filter
   
'filter' => array(
     
'handler'        => 'views_handler_filter_string',
    ),
  );
 
  return
$data;
}
?>

La prima parte (quella nella sezione generic info) riporta delle informazioni base sulla nostra tabella ceh deve essere integrata, in particolar modo il nome, la descrizione e quale è il campo che fa da chiave primaria.

La parte seguente indica come questa tabella è collegata alle altre tabelle del sistema, in particolar modo noi stiamo collegandoci alla tabella node mettendo in relazione i campi nid di entrambe le tabelle.

La terza parte della funzione, invece, ci spiega come devono essere interpretati di diversi campi della tabella, per ogniuno di questi campi che deve essere raggiungbile dalle views si possono definire una serie di informazioni (sorting, field, argument, ...), per ogniuno di questo c'è da inticare un handler, cioè un modo in cui quest'informazione deve essere interpretata (possono essere creati degli handler specifici, ma non affronteremo questo punto ora).

Nel caso in esempio abbiamo detto che i nostri campi sono, il primo, un campo boolenao, mentre il secondo una stringa di testo, di conseguenza il sistema permetterà di effettaure tutta una serie di operazioni su di questi come definitio in appositi file; in particolare sarà possibile usare tutti i meccanismi dei filtri, l'exposition, il sorting, ...

Per conoscere le diverse tipologie di handler disponibili di default vi consiglio di dare un occhiata al contenuto della cartella /sites/all/modules/views/handlers.

L'ultimo punto che affrontiamo è l'inserimento di views predefinite nel nostro modulo. Innanzitutto creiamo la nostra views da interfaccia grafica (a meno che vi vogliate così male da farlo da codice :D ) e andiamo nella pagina di export della views, a questo punto copiamo il codice e inseriamo all'intenro dell'hook_views_default(), otterremo così la nostra views bella e pronta ogni volta che installeremo il nostro modulo.

<?php
/**
* Implementation of hook_views_default_views.
*/
function viewsintegration_views_default_views() {
 
$view = new view;
 
$view->name = 'viewsintegration_lista_articoli';
 
$view->description = 'Elenco degli articoli';
 
$view->tag = '';
 
$view->view_php = '';
 
$view->base_table = 'viewsintegration';
 
$view->is_cacheable = FALSE;
 
$view->api_version = 2;
 
$view->disabled = FALSE;
 
$handler = $view->new_display('default', 'Defaults', 'default');
 
$handler->override_option('fields', array(
   
'title' => array(
     
'label' => 'Title',
     
'link_to_node' => 0,
     
'exclude' => 0,
     
'id' => 'title',
     
'table' => 'node',
     
'field' => 'title',
     
'relationship' => 'none',
    ),
   
'aviable' => array(
     
'label' => 'Disponibilità',
     
'exclude' => 0,
     
'id' => 'aviable',
     
'table' => 'viewsintegration',
     
'field' => 'aviable',
     
'relationship' => 'none',
    ),
   
'code' => array(
     
'label' => 'codice',
     
'exclude' => 0,
     
'id' => 'code',
     
'table' => 'viewsintegration',
     
'field' => 'code',
     
'relationship' => 'none',
    ),
  ));
 
$handler->override_option('filters', array(
   
'aviable' => array(
     
'operator' => '=',
     
'value' => '1',
     
'group' => '0',
     
'exposed' => TRUE,
     
'expose' => array(
       
'operator' => '',
       
'identifier' => 'aviable',
       
'label' => 'Disponibilità',
       
'optional' => 1,
       
'remember' => 1,
      ),
     
'id' => 'aviable',
     
'table' => 'viewsintegration',
     
'field' => 'aviable',
     
'relationship' => 'none',
    ),
   
'code' => array(
     
'operator' => 'contains',
     
'value' => '',
     
'group' => '0',
     
'exposed' => TRUE,
     
'expose' => array(
       
'use_operator' => 0,
       
'operator' => 'code_op',
       
'identifier' => 'code',
       
'label' => 'Codice prodotto',
       
'optional' => 1,
       
'remember' => 1,
      ),
     
'case' => 0,
     
'id' => 'code',
     
'table' => 'viewsintegration',
     
'field' => 'code',
     
'relationship' => 'none',
    ),
  ));
 
$handler->override_option('access', array(
   
'type' => 'none',
  ));
 
$handler->override_option('style_plugin', 'table');
 
$handler->override_option('style_options', array(
   
'grouping' => '',
   
'override' => 1,
   
'sticky' => 0,
   
'order' => 'asc',
   
'columns' => array(
     
'title' => 'title',
     
'aviable' => 'aviable',
    ),
   
'info' => array(
     
'title' => array(
       
'sortable' => 0,
       
'separator' => '',
      ),
     
'aviable' => array(
       
'sortable' => 0,
       
'separator' => '',
      ),
    ),
   
'default' => '-1',
  ));
 
$handler = $view->new_display('page', 'Page', 'page_1');
 
$handler->override_option('path', 'product-list');
 
$handler->override_option('menu', array(
   
'type' => 'normal',
   
'title' => 'Elenco prodotti',
   
'weight' => '0',
   
'name' => 'navigation',
  ));
 
$handler->override_option('tab_options', array(
   
'type' => 'none',
   
'title' => '',
   
'weight' => 0,
  ));
 
$views[$view->name] = $view;
  return
$views;
}
?>

Vederemo le prossime volte come andare a creare dei propri handler e andare a creare delle estensioni "più particolari" per views.

Se nel frattemo vi sorgono domande non esitate a farle :D

AllegatoDimensione
Modulo di esempio2.95 KB

Altri contenuti che potrebbero interessarti

  • Tabella paginata e ordinabile
    Nella realizzazione di interfaccie di report può capitare di dover creare delle tabelle che visualizziino una serie di informazioni. Spesso, se i dati sono molti, è necessario ricorrere alla creazione di tabelle paginate. In altri casi, o in aggiunta a questo, può essere necessario andare a...
  • Precedentemente avevo scritto una patch per views che pemetteva di andare ad indicare delle classi specifiche alle singole righe delle views. Considerato che modificare il codice di un modulo lo considero una delle cose più pericolose nonché sbagliate, e in considerazione del fatto dell'enorme...
  • Interfaccai di presentazione della documentazione delle API di Drupal in gedit
    Non sono ancora riuscito a convincervi ad usare gedit, nonostante i fantastici snippet? vediamo se ques'altra estensione per Drupal vi invonglierà a tentare il passaggio. Cosa serve ad uno sviluppatore? Sicuramente poter accedere alla guida del sitema che sta usando velocemente, e quindi cosa cè di...
  • Caricamento di un form tramite ajax
    Nella creazione di form può essere necessario procede con passi successivi in una serie di scelte, questo comporta una perdita di tempo per gli utenti e quindi è molto comodo sfruttare le potenzialità offerte da ajax per effettuare questi passaggi in cascata senza dover andare a ricaricare la...

Commenti

Ritratto di Lorenzo

campi in interfaccia grafica

grazie tantissimo per il tutorial, veramente utile e molto chiaro!

Ho provato ad adattarlo a un mio modulo, ma non visualizzo l'unico campo della mia tabella all'interno dell'interfaccia per costruire le viste.

Hai idea di dove potrebbe essere l'errore?

ciao e grazie ancora!

Ritratto di Fabio

A quando il seguito

Complimenti per il tutorial che, come tutti gli altri dedicati a Drupal, è completo, esauriente e di qualità introvabile in lingua italiana. Hai intenzione veramente di dare un seguito all'argomento views? Ci sarebbe un grande bisogno di pubblicazioni autorevoli e professionali in lingua italiana, per caso non è che puoi rendere disponibile qualche tuo appunto a buon prezzo?

Ritratto di mavimo

Ciao, grazie per i

Ciao, grazie per i complimenti, sono sempre graditi :)

Per quanto riguarda views, proprio in questi giorni stavo scrivendo un paio di articoli al riguardo, purtroppo il tempo è sempre poco quindi non so dirti quando verranno pubblicati :(

Ritratto di Daniele

errata corrige?

invece di:

$data['node']['table']['join'] = array(

forse:

$data['viewsintegration']['table']['join']['node'] = array(

ho provato con la prima, ma tutti viene visualizzato solo i filtri specificati nella tabella, con la seconda vedo anche tutti gli altri filtri.

Una domanda, invece per far si che i filtri sui campi suddetti vadano invece a far parte di una vista standard del tipo "Node"?

Ritratto di mavimo

Diciamo che dipende da come

Diciamo che dipende da come vuoi fare le join, in ogni caso, la tua soluzione sembra essere un pò più pilita, ma al contempo effettua una join nel senso contrario, quindi dipende dal tipo di relazioni che hai sulle tabelle che vuoi unire.

Ritratto di Roberto

Grazie, ma se..

Grazie per il tutorial..Davvero utile. Ma se si volessero usare i campi del nostro modulo all'interno di una views già definita? ( a me serve integrare dei campi all'interno della view Calendar)...Ciao!

Ritratto di mavimo

Creei i campi aggiuntivi e

Creei i campi aggiuntivi e poi li aggiungi nella views di partenza... o forse non ho capito la tua domanda?

Ritratto di Gianluca

CKK

Forse è una domanda sciocca, ma perchè usare tutto questo anzichè CKK, che è già integrato in View? Non sto provocando, vorrei solo capire, avendo a che fare anch'io con campi aggiuntivi, che però gestisco con CKK

Ritratto di mavimo

Perchè non sempre CCK fornisce i pezzi che ci servono

Perchè non sempre CCK fornisce i pezzi che ci servono (tanto per fare un esempio), oppure perchè l'elemento che stiamo costruendo noi non è un nodo (e quindi CCK non può essere usato), o per altre 1000 ragioni, in ogni caso sono conscio che sia un esigenza limitata (basta vedere quanta poca gente legge e cerca queste informazioni :D)

In ogni caso grazie del commento

Ritratto di Anonimo

e Per effettuare una vista di

e Per effettuare una vista di una tabella
appartenente ad un database situato su un'altro server?

Ritratto di mavimo

Non mi risulta che views

Non mi risulta che views possano effettare elaborazioni di strutture disposte su più database, quindi temo non sia possibile, diverso (litigando un attimo) se tuutta la vista si trova sull'altro database.

Ritratto di eliosh

Relativamente a viewsintegration_views_default_views()

Nel corpo della funzione in oggetto lavori sulla variabile $view mentre alla fine restituisci $views. Credo sia un refuso ma ne approfitto per farti una domanda: se ne devo esportare "n" di viste, le esporto come array di oggetti?
E quindi cambierei la funzione in oggetto da

<?php
return $views;
?>

a

<?php
return array($view);
?>

Is it correct?

Ritratto di mavimo

Si refuso mio, avevo

Si refuso mio, avevo dimenticato di inserire:

<?php
  $views
[$view->name] = $view;
?>

e si, se si vogliono avere più views di default si possono inserire nell'array di ritorno della funzione.

Invia nuovo commento





  • Elementi HTML permessi: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <h2> <h3> <h4> <table> <thead> <tbody> <tr> <th> <td>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Linee e paragrafi vanno a capo automaticamente.
  • Indirizzi web o e-mail vengono trasformati in link automaticamente

Maggiori informazioni sulle opzioni di formattazione.



Condividi contenuti