Più che una guida completa, riporto in queste pagine alcuni appunti su ciò che ho potuto capire leggendo la Guida in linea in drupal.org e lavorando a questo e ad altri siti.
Non nascondo che quando ho iniziato a lavorare con Drupal, ho avuto forti perplessità e difficoltà a comprendere questo CMS. Ne esistevano altri più intuitivi, meno tecnici. Però ne sentivo parlare molto bene e quindi sono andato avanti.
L'approccio iniziale a Drupal è quello di provare gli svariati temi disponibili, attivare modulli, leggere la documentazione ufficiale inglese (per me molto dispersiva) e quel poco che si trova in rete, in italiano, in siti e forum. Inizialmente ho girato dentro al codice cercando di capire come funzionasse, cercando di modificare i temi, arrabbiandomi quando le cose non funzionavano. Ma alla fine mi rendevo sempre conto di non sapere ancora bene dove mettere le mani. Mano a mano che capivo come risolvere qualcosa , me l' appuntavo e alla fine è nata la sezione Come fare per.
Dopo lungo girovagare per il codice , alla fine mi si sono schiarite un po' le idee, quando mi sono chiesto: Ma cosa fa Drupal quando parte? Logico, legge il file index.php. Allora ho cominciato a seguire il codice dall'inizio e finalmente mi si sono schiarite le idee (credo). Ho cominciato a capire cosa veramente è un nodo e come è salvato, cosa sono i file templete e quando sono utilizzati, cosa è un tema etc.
Ecco perchè in questi miei appunti ho messo tra i primi argomenti proprio l' Avvio di Drupal, cercando di spiegare, e mentre scrivevo di fermare le idee, cosa succede da quando viene letto il file index.php a quando termina la presentazione della home page. Ho cercato di approfondire l'argomento in modo tale da poter controllare la situazione e capire meglio gli argomenti successivi. Ci sono ancora delle lacune, ma credo sia un buon punto di partenza per avvicinarsi a Drupal.
Ovviamente per approfondire gli argomenti trattati è d'obbligo la guida ufficiale di drupal.org, e i forum di drupalitalia.org e di drupal.it
Però , andate anche, in questo sito, alla pagina Drupal e al paragrafo "Ma si parla di Drupal anche in ..." dove riporto alcuni link verso siti che ritengo veramente ben fatti e da cui è possibile "attingere sapere" e imparare molte cose su Drupal. Buona lettura
Questa sezione della guida è dedicata a quei piccoli problemi che ho incontrato durante lo sviluppo con Drupal a cui però non avevo trovato , nei vari forum su Drupal , risposta immediata.
Come amministratore del sito, andando sulla voce di menu amministra->impostazioni compare la pagina con tutte le impostazioni del sito. Su impostazioni generali è possibile definire il titolo del sito, la email e l'icona.
Se è stata disabilitata la visualizzazione del Login , collegarsi con www.miosito.it/user, per far comparire la pagina di login.
Provare in uno di questi modi:
Provare a collegarsi con www.miosito.com/user, per far comparire la pagina di login. Se si visualizza entrare come amministratore e riportare il sito on-line.
Controllare se nella tabella variable c'è un record con name= 'site_offline': se c'è cancellarlo insieme al record della tabella cache con cid='variables'
Se ancora non funziona il controllo del sito offline è fatto in includes/menu.inc funzione _menu_site_is_offline() chiamata dalla funzione menu_execute_active_handler()
Verificare 'impostazione della variabile $db_url nel file /sites/defaultl/settings.php
Se ancora non funziona il controllo del sito offline è fatto in includes/menu.inc funzione _menu_site_is_offline() chiamata dalla funzione menu_execute_active_handler()
Per eseguire un Log-out non da menu chiamare la pagina http://miosito.com/logout
L'apertura di una nuova finestra viene eseguita impostando l'attributo "target" nel tag href.
La funzione di default che prepara il tag href e' la funzione theme_menu_item_link() (contenuta in includes/menu.c).
Dobbiamo quindi creare una delle due seguenti funzioni in modo tale che Drupal le possa chiamare in sostituzione della funzione di default.
Le due funzioni, da inserire nel file template.php, sono:
- miotema_menu_item_link($link)
- phptemplate_menu_item_link($link)
Se esistono entrambe , Drupal darà la precedenza a miotema_menu_item_link($link).
Considerando ad esempio la seconda, possiamo fare in modo che l'attributo Target sia presente se il riferimento al link inizia con "http" indicando un percorso esterno al sito. Ecco il codice.
Per versione 6.x
<?php
function phptemplate_menu_item_link($link) {
if (empty(
$link['localized_options'])) {
$link['localized_options'] = array();
}
if( strtolower(substr($link['href'],0,4))=="http") {
$link['localized_options']['attributes'] = array('target' => '_blank');
}
return
l($link['title'], $link['href'], $link['localized_options']);
}
?>In alternativa possiamo sfruttare l'attributo $link[external]=1 che Drupal fornisce nel caso il link sia esterno. Ecco il codice.
<?php
function phptemplate_menu_item_link($link) {
if (empty(
$link['localized_options'])) {
$link['localized_options'] = array();
}
if ($link['external']==1) {{
$link['localized_options']['attributes'] = array('target' => '_blank');
}
return l($link['title'], $link['href'], $link['localized_options']);
}
?>Per versione 5.x
<?php
function theme_menu_item_link($item, $link_item) {
$attributes = array();
if (!empty($item['description'])) $attributes['title'] = $item['description'];
if( strtolower(substr($link_item['path'],0,4))=="http") {
$attributes['target'] = "_blank";
}
return l($item['title'], $link_item['path'], $attributes, isset($item['query']) ? $item['query'] : NULL);
}
?>Attenzione , se il tema che si sta utilizzando implementa la funzione miotema_menu_item_link() nel file template.php, inserire la patch anche in questa funzione.
Per sistemi Windows e server Apache fare le seguenti modifiche:
essendo C:/drupal la documentRoot di Apache Come sono ordinati i contenuti nella rima pagina?
Quindi affinché un contenuto compaia in prima pagina nella tabella NODE si deve avere: Quindi, al di là della data di creazione, per portare un commento al primo posto nella pagina, basta assegnarli (direttamente nella tabella NODE) il valore di sticky più alto in assoluto e via via decrescente per i contenuti che devono seguire. Ci sono due modi per modificare il proprietario del nodo. Attenzione: il nuovo utente potrà ora modificare il contenuto solo se in Controllo accessi ha il permesso amministra filtri nel modulo filter oppure se il formato del contenuto è Filtered HTML. Nel caso non fosse così, permessi non assegnati o formato uguale a PHP code o Full HTML, è necessario o cambiare il permesso o impostare il formato a Filtered HTML. 2. Il secondo metodo consiste nel modificare il campo uid nella tabella node inserendo il valore uid assegnato all'utente (vedere tabella users). Vale la stessa considerazione fatta precedentemente per il formato. Il valore del formato selezionato è comunque indicato nella tabella node_revisions nel campo format per il/i record con campo nid uguale al valore nid del nodo nella tabella node. Format = 1 Filtered HTML valore di default per tutti gli utenti Compare solamente il contenuto senza sidebar intestazione etc. Drupal 6.x Voglio ora inserire dopo il messaggio il risultato di una vista creata mediante l' interfaccia delle viste. Dove page_1 è il nome del display_id da visualizzare definito nell'interfaccia della vista. Come amministratore andare alla pagina delle "impostazioni globali" dei temi. (/admin/build/themes/settings/global) Eseguire la query: global $theme_path Per verificare se l'utente corrente appartiene ad uno dei ruoli definiti nella tabella ROLE
in httpd.conf1. scommentare LoadModule rewrite_module modules/mod_rewrite.so
2. impostare AllowOverride All in ..
<Directory "C:/drupal">
AllowOverride All
Options None
Order allow,deny
Allow from all
</Directory>Ordinare i contenuti nella prima pagina
All'avvio di Drupal viene eseguita la funzione node_page_default() , contenuta in includes/node.module. In questa funzione viene eseguita la seguente query per vedere quali contenuti devono essere inseriti in prima pagina.SELECT n.nid, n.sticky, n.created FROM node n
WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC
promote = 1 ; cioè promosso in prima pagina.
status = 1; cioè pubblicato.
L'ordinamento è fatto sui due campi: sticky(opzione fisso in cima alla lista ) e created (data creazione) e su entrambi in modo discendente.
Per il campo sticky più è alto il valore più il commento sarà in cima alla lista.
Per il campo created , i commenti più recenti saranno visualizzati per primi.
Per tutti i contenuti che si vogliono visualizzare in base alla loro data di creazione, basta mantenere sticky=0.
Attenzione:se ad un contenuto si assegna l'opzioe "fisso in cima alla lista" il valore di sticky sarà posto=1 sovrascrivendo eventuali valori da noi impostati direttamente nella tabella NODE.Cambiare il proprietario di un contenuto
1. Il primo consiste nell'entrare nel nodo del contenuto come amministratore e nelle informazioni sull'autore inserire il nome dell'utente a cui dare la proprietà del nodo.
La tabella node_revisions ha anche il campo uid che per correttezza dovrebbe essere posto uguale al valore in tabella node, ma anche se mantiene il precedente valore non inficia il cambiamento del proprietario.
Format = 2 PHP code
Format = 3 Full HTMLI fogli di stile non sono caricati
Usare una vista nel codice PHP
Views 2.0
Supponiamo di avere un modulo che chiama la funzione miomodulo_output () generando un output per il contenuto principale.<?php
function miomodulo_output () {
$output = "Messaggio di prova";
return $output;
}
?>
Il nome della vista è "vista_di_prova" e accetta in ingresso un argomento numerico passato alla funzione miomodulo_output().
Al codice precedente dobbiamo aggiungere una sola riga:<?php
function miomodulo_output ($arg1) {
$output = "Messaggio di prova<br>";
$output .= views_embed_view('vista_di_prova', 'page_1',$arg1);
return $output;
}
?>
Per approfondimenti
http://drupal.org/node/48816Eliminare la data ed il nome utente da una pagina
Per ogni tipo di contenuto presente nella sezione "Mostra le informazioni del contenuto su",
eliminare il segno di spunta sul tipo di contenuto su cui non si vuole mostrare nome e data.Ripristinare la password di amministratore
UPDATE users SET pass = MD5( 'NUOVAPASSWORD' ) WHERE uid =1;
Per saper il nome associato all'amministratore:
SELECT name FROM users WHERE uid =1;
Ulteriori informazioni possono essere lette direttamente dalla tabella users degli utenti.Conoscere la directory di ...
Cosa
come
directorydel sito
global $base_url
directory di un modulo
$path = drupal_get_path('module', 'nomemodulo');
directory di un tema
$path = drupal_get_path(theme', 'nometema');
directory di un engine
$path = drupal_get_path(theme_engine', 'nomeengine');
directory tema corrente
global $theme_path
Utenti: Sapere se un utente appartiene a un ruolo
definire la seguente funzione:<?php
/**
* @param $role Il nome del ruolo da verificare
* @param $user Oggetto utente
* @return TRUE se l'utente appartiene al ruolo richiesto , FALSE altrimenti
*/
function user_has_role($role, $user = NULL) {
if ($user == NULL) {
global $user;
}
if (is_array($user->roles) && in_array($role, array_values($user->roles))) {
return TRUE;
}
return FALSE;
}
?>
In questa documentazione sarà indicato con il termine di contenuto l'informazione archiviata in un sistema CMS come Drupal.
L'informazione pubblicata è orientata alla diffusione di conoscenza , idee, proposte e altro che gli ideatori del sito hanno come loro missione. L'informazione è resa disponibile nel sito web sotto forma di articoli, libri, forum e ancora con il supporto di immagini , video e suoni.
Tutto questo è quello che chiameremo contenuto primario del sito.
Ma oltre al contenuto primario, nel sito sono presenti altri contenuti come i menu per la navigazione, maschere per l'interazione con l'utente, commenti agli argomenti lasciati dai visitatori o utenti del sito, pubblicità e tutto ciò che può essere necessario per raggiungere lo scopo finale per cui il sito è stato pensato.
Tutto questo è quello che chiameremo contenuto secondario del sito
Il contenuto primario viene gestito dal Drupal attraverso i NODI.
Possiamo pensare al nodo come il contenitore della nostra informazione che viene poi visualizzato sul web sotto forma di pagina singola o di pagina di un libro o ancora come contenuto di un singolo intervento in un forum.
Drupal mette a disposizione dei nodi di base come appunto la creazione di una singola pagina o di un pagina appartenente ad un libro come questa che state leggendo. Ma Drupal consente anche di creare nuove tipologie di nodi. Si potrebbe creare quindi una rubrica telefonica dove ogni nodo è costituito da un singolo nominativo , uno scadenzario, un reportage fotografico e così via.
Il contenuto secondario viene gestito da Drupal attraverso i BLOCCHI.
I menu di navigazione sono dei blocchi, l'elenco degli ultimi commenti alle pagine o delle ultime discussioni aperte in un forum sono dei blocchi, la maschera di login è un blocco così come i tag di ricerca delle pagine. In pratica, come detto, tutto ciò che è utile per una buona navigazione e fruibilità del sito va a finire in un blocco.
Come descritto in Avvio di Drupal il contenuto primario e secondario è letto rispettivamente dalle due funzioni:
Queste due funzioni sono contenute nel file index.php che è il primo ad essere eseguito ad ogni caricamento di pagina.
Per utilizzare Drupal, è fondamentale capire i concetti di event , hook, action e operazione
Drupal è un sistema software che lavora essenzialmente su tre fasi:
Se non ci fosse un modo per interaggire dall'esterno, Drupal sarebbe un sistema completo, non espandibile.
Potremmo pensarlo come un frigorifero:
Sicuramente a un frigorifero non si potrà mai chiedere di fare il caffè!
Fortunatamente , come per la maggior parte dei sistemi software, non è così.
Eventi
Drupal interagisce con il mondo esterno tramite eventi.
Gli eventi (in inglese events) indicano al mondo esterno cosa sta succedendo all'interno della macchina Drupal.
Eventi possibili sono ad esempio :
Ma l'evento è un concetto astratto. Ad esso deve corrispondere qualcosa di concreto che consenta di agganciarsi al flusso di elaborazione di Drupal per modificarlo.
In pratica ad ogni elaborazione Drupal dice:
Hook
A questo punto è chiaro che un Hook o Gancio è qualcosa che ci permette di dare un nome predefinito ad una funzione in modo tale che possa essere riconosciuta ed eseguita da Drupal quando si verifica l'evento,
Facciamo l'esempio in cui un utente esegue il login al sistema.
Vogliamo creare un' azione che su questo evento visualizzi il messaggio "Benvenuto nel sito"
Il modulo che contiene le funzioni supponiamo si chiami miomodulo.
La funzione che sarà necessario scrivere è la seguente:
<?php
function miomodulo_user($op,&$edit,&$account,$category=NULL) {
if($op== 'login') return "Benvenuto nel sito";
}
?>Infatti:
Dove Operazione =' login' è l'operazione particolare della coppia Evento/Hook
Ad esempio lo stesso evento e lo stesso hook sono utilizzabili anche per una operazione di cancellazione (delete) di un utente. In tal caso la funzione sarebbe stata scritta nel seguente modo:
<?php
function miomodulo_user($op,&$edit,&$account,$category=NULL) {
if($op== 'login') return "Benvenuto nel sito";
if($op== 'delete') return "Grazie di essere stato con noi!";
}
?>Quindi per eseguire un'azione sul verificarsi di un evento , basta generare la funzione:
nomemodulo_hook($op);
Verificando all'interno il tipo di operazione avviata su quell'evento.
Quando un browser invia un URL a Drupal per richiedere una pagina , la prima azione che viene eseguita dal sistema è la lettura del codice php nel file index.php.
Nel file, riportato a fondo pagina, sono definite le quattro fasi distinte che Drupal esegue per portare a termine la visualizzazione della pagina richiesta.
Il sistema chiama la funzione drupal_bootstrap() che inizializza tutte le variabili di sistema , carica i moduli attivi , si connette al database, converte l'url alias ed altro ancora, predisponendo l'ambiente alla lettura e codifica dei contenuti.
Il sistema chiama la funzione menu_execute_active_handler() che legge e codifica il contenuto richiesto, tornando una stringa contenente il codice HTML da visualizzare. In questa fase Drupal individua, in base al path ricevuto, la page callback, che consente di estrarre il contenuto della pagina.
Ad esempio per un nodo generico la page callback è la node_page_view().
In pratica viene preparato tutto tranne le barre, l'intestazione, il piè di pagina.
Per un esempio di quello che Drupal genera in questa fase, aprire il file index.php
e aggiungere le due righe indicate sotto la funzione menu_execute_active_handler().
...... $return = menu_execute_active_handler(); print $return; exit(); ....
Richiamando ora la home page del sito si vedrà il solo contenuto della pagina senza barre laterali, intestazione e fondo pagina. Questo perchè $return contiene il codice HTML del contenuto ed è quello che viene stampato con l'istruzione print $return.
E' da notare che al risultato non sono applicati gli stili del tema corrente, poichè il tema, e quindi lo stile, non è ancora stato completamente applicato cosa che viene fatta successivamente chiamando la funzione theme('page',$return).
Il sistema chiama la funzione theme('page') che legge e codifica il contenuto secondario unendolo al primario. Il risultato ottenuto è inviato al browser mediante l'istruzione "print".
Anche qui è possibile isolare il risultato ottenuto sostituendo il parametro $return con una stringa vuota, come in esempio:
......
$return=""; // annulla $return
print theme('page', $return);
}
...
Richiamando ora la home page del sito si vedrà il solo contenuto secondario, intestazione, blocchi, menu ma senza il contenuto primario definito in $return.
Il sistema chiama la funzione drupal_page_footer(). Nelle fasi precedenti sono state avviate tutte le funzioni per preparare i contenuti. In questa fase Drupal chiama tutte le funzioni hook_exit() implementate nei moduli attivi, per avvisare che la pagina richiesta è stata inviata e che le operazioni da attivare sono terminate.
Queste funzioni possono essere utili per eseguire un debugging del sistema o aggiornare, in fase di chiusura, alcune tabelle associate ai moduli.
Contenuto del file index.php.
<?php
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
/*
Con questa funzione viene generato
il solo contenuto dei nodi e, al ritorno, nella variabile $return
è presente il codice HTML del contenuto dei nodi.
*/
$return = menu_execute_active_handler();
// Menu status constants are integers; page content is a string.
if (is_int($return)) {
switch ($return) {
case MENU_NOT_FOUND:
drupal_not_found();
break;
case MENU_ACCESS_DENIED:
drupal_access_denied();
break;
case MENU_SITE_OFFLINE:
drupal_site_offline();
break;
}
}
elseif (isset($return)) {
// Print any value (including an empty string) except NULL or undefined:
/*
Con questa funzione viene generato il contenuto dei blocchi ,
assemblato insieme al precedente contenuto dei nodi
e visualizzato sul web
*/
print theme('page', $return);
}
/*
* Preparazione della parte finale della pagina
*/
drupal_page_footer();
?>Riporto di seguito la descrizione maggiormente dettagliata di quel che succede nelle quattro fasi suddette.
Drupal è un sistema in cui le pagine richieste sono quasi sempre costruite dinamicamente.
Il testo della pagina è archiviato in un database e quando viene richiesto, Drupal deve leggerlo e trasformarlo in codice HTML per essere visualizzato sul browser.
Drupal è quindi un sistema che genera pagine dinamiche.
Quando un browser invia un URL per richiedere una pagina del sito ,il sistema deve individuare dall' URL quale funzioni attivare per generare e visualizzare la pagina richiesta.
Il meccanismo che individua le funzioni da richiamare è descritto qui di seguito.
La variabile $_GET['q'] , e il suo valore , è resa disponibile dal server web.
Il server web imposta il valore di $_GET['q'] al percorso richiesto interno al sito, in seguito indicato con il termine path. E' dal valore di questa variabile che Drupal parte per determinare quale funzione attivare per visualizzare il contenuto richiesto.
Ad esempio:
se l' URL=http://miosito.com allora $_GET['q'] = ''
se l' URL=http://miosito.com/node/345 allora $_GET['q'] = node/345
se l' URL=http://miosito.com/contabilita/elenco-fatture/attive allora $_GET['q'] = contabilita/elenco-fatture/attive
Se l' URL inviato contiene il solo nome del sito www.miosito.com e quindi $_GET['q'] = "", Drupal non effettua alcuna conversione riconoscendo nell' URL la richiesta della home page del sito.
In questo caso Drupal forza $_GET['q'] = "node".
L'URL inviato al sistema, può contenere un alias dell'URL, come nell'esempio di "miosito.com/contabilita/elenco-fatture/attive". Il path contenuto nella variabile $_GET['q'] in questo caso sarà uguale a "contabilita/elenco-fatture/attive".
Il sistema per prima cosa converte il path ricevuto in un indirizzo interno e successivamente individua la funzione da attivare per estrarre dal database il contenuto richiesto.
La conversione viene eseguita nella fase di bootstrap, a cui si rimanda , ed in particolare nella fase di BOOTSTRAP_PATH.
In questa fase Drupal cerca nella tabella URL_ALIAS il path "contabilita/elenco-fatture/attive" e se esiste imposta la variabile $_GET['q'] al valore del corrispondente path di sistema.
Esempio: contabilita/elenco-fatture/attive => node/345
A conversione avvenuta avremo $_GET['q'] = node/345 e quindi il sistema saprà quale nodo deve essere visualizzato.
Evidentemente se non si trova una corrispondenza nella tabella indicata, significa che l'URL non contiene un alias e quindi la variabile $_GET['q'] non sarà alterata.
Dopo l'eventuale conversione dell' URL , in $_GET['q'] si trova l'indirizzo reale della pagina da visualizzare.
Drupal deve ora individuare la page_callback, per estrarre e visualizzare il contenuto richiesto.
Abbiamo visto in Avvio di Drupal che all'interno del file index.php la lettura del contenuto viene eseguito dalla funzione menu_execute_active_handler(), il cui codice è parzialmente riportato a fondo pagina.
Questa , al suo interno, chiama la funzione menu_get_item() che individuerà la page_callback, e se specificato, caricherà anche il nodo o l'oggetto richiesto.
In che modo viene individuata la page callback?
La page_callback è individuata grazie alla tabella MENU_ROUTER. In questa tabella sono contenute le informazioni necessarie per individuare la page_callback, il cui nome è indicato nel campo <page_callback>. In particolare la colonna <path> contiene i possibili path parametrizzati che possono essere richiesti.
La tabella MENU_ROUTER è caricata da Drupal, quando si entra nel menu Amministrazione->Elenco moduli e si salva la pagina. Drupal chiamerà tutte le funzioni implementate nei moduli che hanno nome: nomemodulo_menu(). In queste funzioni sono definite le page_callback e tutte le infornazioni necessarie per eseguire le funzione richieste che saranno archiviate nella tabella MENU_ROUTER.Di tutto questo si parlerà nello parte dedicata all sviluppo dei moduli. Ad esempio, volendo modificare il nodo 12345 , potrebbe essere inviato a Drupal il path node/12345/edit.
In questo caso, il sistema cercherebbe nella colonna <path> uno dei seguenti path:
7 node/12345/edit
6 node/12345/%
5 node/%/edit
4 node/%/%
3 node/12345
2 node/%
1 node
Potrebbero non essere tutti presenti, ma tra quelli presenti, l'ordine di selezione è dato dal valore del campo <fit> della tabella.
Il path node/%/edit indica che il record della tabella contiene il nome della page_callback per tutti i path costituiti da 'node', un numero identificativo del nodo , e 'edit' come per 'node/12345/edit'
Individuato il path, il corrispondente record viene posto in un array e tornato alla funzione menu_execute_active_handler() che chiamerà la page_callback.
Oltre a tutti i campi della tabella menu_router, l'array conterrà anche:
$router_item[access] = che indica se si può accede al percorso.
$router_item[href] = equivalente al campo <path>
$router_item[localized_options] per ulteriori opzioni sul path inseribili da altre funzioni.
La funzione menu_get_item() è in grado di leggere l'oggetto richiesto (ad esempio un nodo) se nella tabella MENU_ROUTER è specificata una funzione di caricamento.
La page_callback chiamata è la node_page_default() a cui non vengono passati argomenti. Il valore $router_item[page_arguments] è nullo.
Abbiamo visto ad esempio che per la richiesta node/12345, il sistema trova nella tabella MENU_ROUTER il path 'node/%' e a questo corrispondono i due campi:
<page_callback> : node_page:view()
<load_function>: node_load() (serializzata in tabella)
Essendo presente il nome di una funzione di caricamento, la menu_get_item() sarà in grado di leggere l'oggetto, utilizzando la funzione indicata, e inserirlo in
$router_item[page_arguments] come argomento della funzione di page_callback.
Di seguito un frammento del codice che :
<?php
function menu_execute_active_handler($path = NULL) {
// altro codice ...
if ($router_item = menu_get_item($path)) {
if ($router_item['access']) {
if ($router_item['file']) {
require_once($router_item['file']);
}
return call_user_func_array(
$router_item['page_callback'],
$router_item['page_arguments']
);
}
else {
// altro codice ...
}
}
?>All'avvio di Drupal, il valore di $path è NULL e la funzione menu_get_item() leggerà il path dalla variabile globale $_GET['q'].
La page_callback a questo punto leggerà il contenuto e tornerà una stringa contenente il corrispondente codice HTML.
La funzione drupal_bootstrap() è contenuta nel file ./includes/bootstrap.inc che viene subito caricato. All'interno del file bootstrap.inc sono definite le otto costanti che indicano quale sotto fase attivare nel bootstrap.
Alla funzione drupal_bootstrap() viene passato un parametro che indica a quale fase fermarsi del bootstrap. All'avvio, e in generale su richiesta di un nodo generico, il parametro è posto uguale a DRUPAL_BOOTSTRAP_FULL in modo tale da eseguire tutte le otto le fasi. Le funzioni attivate dalle singole fase sono definite nella funzione _drupal_bootstrap($phase).
1) DRUPAL_BOOTSTRAP_CONFIGURATION
Funzioni utilizzate:
conf_init() inizializza le variabili
conf_path() torna il percorso del file settings.php
2) DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE
Include il file ./includes/cache.inc
Funzioni utilizzate:
_drupal_cache_init()
Inizializzazione della cache.
All'avvio non viene eseguita nessuna operazione.
3) DRUPAL_BOOTSTRAP_DATABASE
Include il file ./includes/database.inc
Funzioni utilizzate:
- db_set_active() Apre la connessione al database definito in settings.php
Apre la connessione al database.
Le funzioni per accedere al database sono definite nel file ./includes/database.$db_type.inc. (tipicamente $db_type=mysql)
Se il file non esiste, Drupal si ferma indicando che non è possibile utilizzare il tipo di database definito in $db_type. Se la connessione va a buon fine viceversa vengono impostati i valori delle seguenti variabili globali:
Se username='username' e password='password' in $db_url di settings.php, Drupal avvia l'installazione del sistema caricando il file instal.php. Il valore di ritorno della funzione db_set_active() è il nome del database precedentemente attivato, FALSE se non ce ne era nessuno.
4) DRUPAL_BOOTSTRAP_ACCESS
Funzioni utilizzate:
_drupal_is_denied()
La funzione drupal_is_denied(), verifica che ci siano i permessi per l'accesso all'host contenente Drupal.
5) DRUPAL_BOOTSTRAP_SESSION
Include il file ./includes/session.inc
Funzioni utilizzate:
session_set_save_handler() (nativa php)
Imposta le funzioni di archiviazione sessioni a livello utente, ed avvia mediante session_start() la gestione della sessione.
6) DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE
Include i file ./includes/cache.inc, ./includes/module.inc
Funzioni utilizzate:
_drupal_cache_init()
Se la cache è abilitata e per la URL fornita esiste un record nella tabella cache, Drupal legge il contenuto della cache, visualizza la pagina e si ferma.
Se la cache non è abilitata o è vuota , Drupal torna dalla funzione _drupal_cache_init() e continua con il bootstrap eseguendo le funzioni e le fasi successive. In particolare in questa fase esegue le seguenti funzioni:
timer_start()
drupal_page_header()
Inizializza l'array globale $conf utilizzata dalla funzione variable_get().
Attiva , mediante drupal_page_header(), le impostazioni del protocollo HTTP per la risposta.
header("Expires: Sun,19 Nov 1978 05:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", FALSE);
7) DRUPAL_BOOTSTRAP_PATH
Include il file ./includes/path.inc
Funzioni utilizzate:
drupal_init_path()
Inizializza la variabile $_GET['q'] al valore 'node'.
8) DRUPAL_BOOTSTRAP_FULL
Include il file ./includes/common.inc
Funzioni utilizzate:
_drupal_bootstrap_full()
E' l'ultima fase del bootstrap del sistema.
La funzione drupal_bootstrap_full() consente di caricare gli ultimi file include:
./includes/theme.inc
./includes/pager.inc
./includes/menu.inc
./includes/tablesort.inc
./includes/file.inc
./includes/unicode.inc
./includes/image.inc
./includes/form.inc
che conterranno le funzioni da utilizzare nelle tre successive fasi (vedi Avvio di Drupal), attivare delle funzioni di inizializzazione del sistema e caricare i moduli abilitati.
L'ultima funzione module_invoke_all('init') invoca tutte le funzioni di inizializzazione del tipo hook_init(), se esistenti, dei singoli moduli.
Gli argomenti trattati fanno riferimento alla versione 5.x di Drupal
In questa fase Drupal visualizza la pagina richiesta utilizzando gli stili del tema impostato e il file page.tpl.php come guida per la costruzione dinamica della pagina.
Per fare questo Drupal chiama la funzione theme('page',$return) a cui passa, come argomenti, il parametro 'page' e il codice HTML del contenuto della pagina preparato nella precedente fase.
La funzione theme()
La funzione theme() individua la funzione corretta da eseguire. In questo caso, in base al parametro passato 'page' , chiamerà:
Generalmente, e consideriamo questo caso, Drupal trova e chiama la funzione phptemplate_page()
La funzione phptemplate_page()
Al suo interno la funzione avvia le seguenti operazioni:
Le barre laterli
Per le barre laterali Drupal definisce la variabile $layout che pone uguale a:left, right, both, none a seconda che sia stata definita la barra laterale sinistra, la destra, entrambe o nessuna. In fase di definizione dello stile del tema, questa variabile può essere usata per definire le dimensioni delle regioni dei contenuti in funzione della presenza o meno delle barre laterali.
Poichè la barre laterali sono costituite da blocchi, Drupal legge tutti i blocchi da visualizzare nella pagina richiesta e genera il corrisondente codice HTML che pone nelle variabili $sidebar_left e $sidebar_right.
Il loop sui blocchi viene eseguito dalla funzione theme_blocks($region), essendo $region la regione da caricare: left o right.
Ogni singolo blocco è formattato con la funzione phptemplate_block() che a sua volta si avvale delle funzioni:
Il processo si ripete per il blocco successivo, fino a completare il codice di tutta la barra laterale.
E' possibile generare la funzione miotema_page($return) in template.php per decidere il valore della variabile $show_blocks che consente di nascondere(=false) o mostrare (=true) le barre laterali.
function miotema_page($return) {
$show_blocks = false
return phptemplate_page ($return,$show_blocks)
}
Gli argomenti trattati fanno riferimento alla versione 6.x di Drupal
I nodi contengono il contenuto primario del sito.
L'elenco di tutti i nodi inseriti nel sistema è contenuto nella tabella NODE.
Le informazioni sono lette e codificate dal sistema, mediante la funzione menu_execute_active_handler(), descritta in Decodifica URL. La funzione individua la page callback e, tramite essa, torna la stringa del contenuto codificato.
Per i nodi sono disponibili due page callback:
La prima pagina del sito mostra generalmente più di un nodo. Questi sono i nodi a cui è stato assegnato l'attributo di pubblicazione "promosso in prima pagina". Per selezionare tali nodi, la funzione node_page_default() esegue la seguente query sulla tabella NODE:
SELECT n.nid, n.sticky, n.created FROM node n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC
Dalla query si vede che le condizioni affinché un nodo venga selezionato sono:
L'ordine di visualizzazione dei nodi è fornito invece dal valore sticky:più è alto, più il nodo salirà nell'elenco. A parità di valore l'ordine è dato dalla data di creazione. I nodi più recenti , sono visti per prima.
Il valore di sticky normalmente vale zero. Volendo quindi mostrare un nodo sempre per primo, indipendentemente dalla data di creazione, basterà assegnare un valore >0 al nodo, ad esempio 100.
Individuati i nodi da visualizzare , la funzione node_page_default(), inizia un ciclo di lettura e visualizzazione di tutti i nodi. Questo viene eseguito all'interno del ciclo contenuto nella funzione node_page_default().
<?php
function node_page_default() {
......
$output = '';
$num_rows = FALSE;
while ($node = db_fetch_object($result)) {
$output .= node_view(node_load($node->nid), 1);
$num_rows = TRUE;
}
// Il valore 1 in node_view indica che si tratta del contenuto teaser
.....
?>All'interno del ciclo sono visibili le due funzioni di Drupal per il caricamento del nodo node_load() e per la visualizzazione del nodo node_view(). Al termine la stringa $output conterrà tutti i contenuti dei nodi da visualizzare in prima pagina.
Se la pagina richiesta non è la home page, ma un singolo contenuto, Drupal seleziona la page callback node_page_view(). Poichè la richiesta di visualizzazione è di un particolare nodo (ad esempio http://miosito.com/node/100), Drupal carica prima il nodo richiesto mediante la funzione node_load() e successivamente chiama la node_page_view() passando le informazioni sul nodo ($node) lette e un identificativo ($cid) che, se non nullo, indica che la pagina del nodo è già presente nella cache.
La funzione node_page_view() imposta il titolo della pagina (drupal_set_title(check_plain($node->title))) e chiama la funzione node_view($node, FALSE, TRUE). Il terzo parametro a TRUE indica che Drupal deve visualizzare l'intero contenuto del nodo.
In definitiva abbiamo visto che le due funzioni di base utilizzate da Drupal sia per la visualizzazione della home page sia per la visualizzazione di un singolo contenuto sono sempre node_load() e node_view().
Il funzionamento di queste due funzioni e quindi la logica del caricamento e della visualizzazione dei nodi è descritto nei successivi paragrafi: Caricamento, Visualizzazione.
node_page_default()
node_page_view()
node_load()
node_view()
node_invoke()
node_invoke_api()
La lettura del contenuto del nodo, è eseguita mediante la funzione node_load($nid) a cui è passato il valore dell'identificativo univoco del nodo <nid> da caricare. Al suo interno viene generata la query indicata, che usa tre tabelle:
Query di selezione
SELECT n.nid, n.type, n.language, n.uid, n.status, n.created, n.changed, n.comment, n.promote, n.moderate, n.sticky, n.tnid, n.translate, r.vid, r.uid AS revision_uid, r.title, r.body, r.teaser, r.log, r.timestamp AS revision_timestamp, r.format, u.name, u.picture, u.data FROM node n INNER JOIN users u ON u.uid = n.uid INNER JOIN node_revisions r ON r.nid = n.nid AND r.vid = <n.nid> WHERE n.nid = <n.nid>
Dala funzione node_load() torna un oggetto ($node) contenente le informazioni lette mediante la query.
In particolare i valori $node->body e $node->teaser conterranno rispettivamente contenuto e sommario del nodo.
Oggetto $node generato dalla funzione.
(ND=da tabella NODE; NR da tabella NODE_REVISIONS; US da tabella USERS)
| $node->nid | ND | identificativo univoco del nodo |
| $node->language | ND | lingua del contenuto:'it' , 'en', 'fr', … |
| $node->type | ND | tipo del nodo. Tabella di codifica NODE_TYPE |
| $node->uid | ND | identificativo utente del proprietario del nodo |
| $node->status | ND | =0 non visibile; =1 visibile |
| $node->created | ND | timestamp della data di creazione del nodo |
| $node->changed | ND | timestamp della data di modifica del nodo |
| $node->comment | ND | identificativo utente dell'ultimo commento |
| $node->promote | ND | =1 il nodo è visualizzato in prima pagina |
| $node->moderate | ND | =1 il nodo deve essere controllato prima della pubblicazione |
| $node->sticky | ND | numero d'ordine del nodo nella prima pagina |
| $node->tnid | ND | set ID traduzione (da capire meglio) |
| $node->translate | ND | Booleano.Indica se la traduzione deve essere aggiornata |
| $node->sticky | ND | numero d'ordine del nodo nella prima pagina |
| $node->vid | NR | identificativo del numero di revisione |
| $node->uid | NR | identificativo utente del proprietario del nodo |
| $node->title | NR | titolo del nodo per la revisione corrente |
| $node->body | NR | contenuto del nodo per la revisione corrente |
| $node->teaser | NR | sommario del nodo per la revisione corrente |
| $node->log | NR | Messaggio di log contenente le modifiche eseguite |
| $node->revision_timestamp | NR | data di modifica del nodo |
| $node->format | NR | formato del nodo da tabella FILTERS_FORMAT |
| $node->name | US | nome utente |
| $node->picture | US | percorso all'immagine utente |
| $node->data | US | serializzazione di un array che rappresenta i campi dela form utente |
Oltre alla lettura delle informazioni contenute specificatamente nelle tabelle NODE e NODE_REVISIONS, Drupal consente di aggiungere ulteriori informazioni ai nodi e quindi all'oggetto $node.
Potremmo decidere di definire un nuovo tipo di nodo con informazioni aggiuntive salvate in una tabella separata.
Pensiamo ad esempio ad una rubrica telefonica. Il nominativo e l'identificativo univoco potrebbero essere rispettivamente il campo <title> e il campo <nid> della tabella NODE, mentre tutte le informazioni aggiuntive come l'indirizzo, il telefono, l'email etc, potrebbero essere memorizzate in una tabella separata.
Si pone quindi il problema di leggere queste ulteriori informazioni associate ai nodi.
Drupal consente di leggere queste extra informazioni implementando funzioni particolari che gestiscano queste situazioni.
Dobbiamo distinguere due casi:
Nella tabella NODE_TYPES sono elencati il tipo di nodi definiti nel sistema. Tra questi sono presenti i nodi principali, forniti con il sistema, quali: page, book, story etc.
Dalla stessa tabella vediamo che il campo <module> ci dice da quale modulo sono gestiti i nodi.
Ora supponiamo di aggiungere il nuovo tipo di nodo "rubrica" e che questo tipo di nodo sia gestito dall'omonimo modulo con tutte le sue funzioni implementate in rubrica.module. Ora quando Drupal leggerà un nominativo dal nodo rubrica, nominativo e identificativo saranno letti come indicato nel precedente paragrafo, mentre l'ulteriore contenuto sarà letto chiamando la funzione rubrica_load($node). La funzione deve tornare un array associativo costituito dalle coppie chiave=valore. Un esempio di semplice codice è il seguente:
<?php
function rubrica_load($node) {
// rid = identificativo nominativo ;
$r = db_fetch_object(db_query('SELECT telefono, indirizzo,citta FROM {rubrica} WHERE rid = %d ', $node->nid));
info = array();
info['telefono'] = $r->telefono;
info['indirizzo'] = $r->indirizzo;
info['citta'] = $r->citta;
return $info;
}
?>All'oggetto $node originale, Drupal aggiungerà le informazioni:
| $node->telefono |
| $node->indirizzo |
| $node->citta |
La funzione è chimata all'interno di node_load() mediante node_invoke($node,'load');
Attenzione:Nel caso il modulo di gestione sia quello di default node, il nome della funzione deve essere node_content_load() e non node_load() come dovrebbe.
In questo caso viene chiamata una funzione per avvisare altri moduli che si sta caricando un nodo.
Infatti la funzione non appartiene al modulo che gestisce il tipo di nodo come nel caso precedente , ma ad altri moduli attivi.
A questo punto la funzione chiamata potrebbe compiere due diverse operazioni:
In entrambi i casi possono dunque essere aggiunte o meno extra informazioni all'oggetto $node.
La funzione da implementare deve chiamarsi nomemodulo_nodeapi($node,$opz).
A questa funzione è passato l'oggetto $node e il valore $opz='load. che indica l'operazione che si sta eseguendo sul nodo .
Un esempio di semplice codice, nel caso in cui venga aggiunta informazione a $node, è il seguente:
<?php
function rubrica_nodeapi($node,$opz) {
switch (
$opz) {
case 'load':
info = array();
info['telefono'] = $r->telefono;
info['indirizzo'] = $r->indirizzo;
info['citta'] = $r->citta;
return $info;
break;
default:
break;
}
?>La funzione è chiamata all'interno di node_load() mediante node_invoke_nodeapi($node,'load');
La funzione node_load() per ogni nodo letto chiama tutte le funzioni implametate in questo modo.
Abbiamo visto che la funzione node_load() insieme ad altre funzioni di integrazione, genera l'oggetto $node con tutte le informazioni sul nodo e, tra queste, quelle sul corpo ($node->body) e sul sommario ($node->teaser). Drupal deve ora leggere queste informazioni,e prepararle alla visualizzazione finale. La fase di preparazione del contenuto usa quindi la funzione node_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE). Il parametro $node è l'oggetto nodo; $teaser indica se visualizzare o meno il sommario; $page indica se visualizzare o meno l'intero contenuto del nodo; $links indica se visualizzare o meno i links associati al nodo.
Ma perchè è necessaria la fase di preparazione dei contenuti? Ci sono diversi motivi, ad esempio:
In questa fase Drupal genera l'array $node->content[<campo>] che contiene tutti i contenuti del nodo, sia del campo body sia di tutti i campi aggiunti dai moduli esterni a quella tipologia di nodo.
Vediamo quindi quali sono i passi che portano alla definizione del contenuto da visualizzare.
Per fare questo di seguito è riportato integralmente il codice della funzione node_view()
<?php
function node_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE) {
$node = (object)$node;
// ############## FASE 1
$node = node_build_content($node, $teaser, $page);
// ############## FASE 2
if ($links) {
$node->links = module_invoke_all('link', 'node', $node, $teaser);
drupal_alter('link', $node->links, $node);
}
// Set the proper node part, then unset unused $node part so that a bad
// theme can not open a security hole.
// ############## FASE 3
$content = drupal_render($node->content);
if ($teaser) {
$node->teaser = $content;
unset($node->body);
}
else {
$node->body = $content;
unset($node->teaser);
}
// ############## FASE 4
// Allow modules to modify the fully-built node.
node_invoke_nodeapi($node, 'alter', $teaser, $page);
// ############## FASE 5
return theme('node', $node, $teaser, $page);
}
?>La funzione comprende cinque fasi:
1.Costruzione del contenuto
Per prima cosa la funzione node_build_content (costruzione del contenuto) genera l'array $node[content].
2. Costruzione dei links del contenuto
Se richiesti i links nel contenuto, Drupal chiama tutte le funzioni dei moduli esterni che implementano la funzione nomemodulo_link($node,$teaser) e successivamente consente di modificare i links costruiti chiamando la funzione, se esistente, nomemodulo_tiponodo_alter(). Ad esempio avendo un tipo nodo rubrica e gestito dal modulo node, la funzione si chiamerà node_rubrica_alter().
3. Rendering del contenuto
Drupal esegue il rendering dei campi definiti in $node->content. Il risultato è una stringa che viene copiata in $node->body o $node_teaser in funzione dei valori passati in $page e $teaser.
4. Modifica globale del contenuto
Qui Drupal dà l'ultima possibilità di modificare le informazioni del nodo, contenuto e links inclusi, prima di applicare il tema corrente e di visualizzare il nodo.i
5. Tematizzazione del contenuto
Al termine il contenuto costruito viene tematizzato per la definitiva visualizzazione. Per un nodo generalmente è usato il template node.tpl.php.
Avvia la costruzione del contenuto del nodo mediante la node_build_content($node, $teaser, $page);
Qui, la preparazione dell'array $node[content] può avvenire mediante due funzioni:
1. Una funzione personalizzata
2. La funzione standard node_prepare()
Drupal legge il tipo di nodo corrente ($node->type) e dalla tabella NODE_TYPE ricava il modulo che gestisce il tipo di nodo, che supponiamo abbia il nome nomemodulo.
Cerca quindi la funzione nomemodulo_view($node, $teaser, $page) e se esiste la chiama.
Nel caso il nodo sia gestito dal modulo "node" la funzione si dovrebbe chiamare node_view, ma poichè questa funzione è quella che stiamo descrivendo, solo per questo caso la costruzione del nome della funzione non segue la regola generale, ma si dovrà chiamare node_content_view() (che comunque non esiste).
La costruzione dell' array $node->content[] per tutti i campi del nodo è quindi totalmente affidata alla funzione personalizzata.
Se non è fornita la funzione personalizzata , Drupal chiama la sua funzione node_prepare()
Qui viene elaborato il contenuto del corpo (body) o del sommario (teaser) del nodo applicando i fitri impostati tramite la funzione check_markup(), di cui parleremo in altra parte. Inoltre imposta il flag $node->readmore= True/False in funzione del valore di $teaser/$page. Al termine è generato il primo pezzo dell'array node->content e precisamente:
node->content['body']['#value'] che contiene il valore del corpo o del sommario del nodo,
node->content['body']['#weight']=0 posizione del corpo del nodo in fase di visualizzazione.
Si pone ora il problema di generare il contenuto di tutti quei campi non standard del nodo, aggiunti eventualmente da altri moduli. Ad esempio se è stato generato un nuovo tipo di nodo usando il modulo CCK, il nodo conterrà campi aggiuntivi che devono essere gestiti dal modulo CCK. Per fare questo Drupal esegue tutte le funzione nomemodulo_nodeapi($node,'view', $teaser, $page).
Gli array node->content['nome campo'] che vengono creati possono avere strutture complesse e non omogenee.
Ad esempio per un campo CCK immagine la struttura che si ottiene è la seguente
$node[content][field_immagine] Array [6] field Array [11] #type content_field #title immagine #field_name field_immagine #access true #label_display above #node stdClass #teaser 1 #page false #context teaser #single true items Array [1] 0 Array [7] #item Array [12] fid 20 list 0 data Array [0] uid 3 filename foto.jpg filepath sites/files/foto.jpg filemime image/jpeg filesize 123453 status 1 timestamp 1265803634 nid 7 #delta 0 #weight 0 #theme filefield_formatter_default #field_name field_immagine #type_name nuovotipo #formatter default #node stdClass #weight 1 #post_render Array [1] 0 content_field_wrapper_post_render #field_name field_immagine #type_name nuovotipo #context teaser
All'oggetto $node sono associati i Links di navigazione del nodo che , generalmente, compaiono al termine del sommario di un nodo in prima pagina. Se presenti sono inseriti nell' array $node->links. Drupal consente di generare l'array $node->links chiamando due funzioni personalizzate:
- nomemodulo_link($type, $node, $teaser = FALSE)
Dove:
$type è il tipo di nodo (ad esempio 'node'),
$node l'oggetto in cui inserire l'array del link,
$teaser indica se il nodo è in prima pagina o meno.
La funzione è chiamata per tutti i moduli che la implementano. Ad esempio node_link(), comment_link() taxonomy_link() etc.
La funzione deve tornare un array contenente le componenti caratteristiche della funzione di costruzione del link: l().
Come esempio di implementazione riporto integralmente la funzione node_link().
<?php
function node_link($type, $node = NULL, $teaser = FALSE) {
$links = array();
if ($type == 'node') {
if ($teaser == 1 && $node->teaser && !empty($node->readmore)) {
$links['node_read_more'] = array(
'title' => t('Read more'),
'href' => "node/$node->nid",
// The title attribute gets escaped when the links are processed, so
// there is no need to escape here.
'attributes' => array('title' => t('Read the rest of !title.', array('!title' => $node->title)))
);
}
}
return $links;
}
?>Come si vede , Il valore di ritorno è l'array $links che sarà aggiunta agli array già definiti. L'oggetto nodo non deve quindi essere modificato all'interno della funzione.
- nomemodulo_link_alter(&$data)
Dopo che l'intero array dei link è stato costruito, Drupal da una ultima opportunità di modificarlo chiamando ancora per tutti i moduli le funzioni nomemodulo_link_alter() passando in &$data il riferimento il valore $node->links.
Il rendering del contenuto (generazione del codice HTML definitivo) avviene mediante la funzione drupal_render(&$elements) chiamata ricorsivamente su tutti i campi del nodo. Il parametro $elements corrisponde all'array precedentemente generata $node->content[]. La funzione torna la stringa $content contenente tutto il contenuto del nodo pronto per essere visualizzato. Il contenuto è copiato in $node->body o in $node->teaser a seconda dei valori $teaser e $page passati alla funzione node_view(). In $node , la variabile in cui non è copiato il contenuto è eliminata da Drupal.
Al''interno della funzione drupal_render(), Drupal ci consente di modificare il contenuto sia prima di eseguire il rendering sia dopo averlo eseguito. Vediamo come.
- Personalizzazione mediante $node->content['#pre_render']
Prima di eseguire il rendering del contenuto, Drupal chiama tutte le funzioni eventualmente definite nell'array $node->content['#pre_render']. Le funzioni possono avere un qualsiasi nome e ad esse Drupal passa tutta l'array $node->content precedentemente generata.
- Personalizzazione mediante $node->content[<campo>]['#pre_render']
Il valore [#pre_render] può essere assegnato ad ogni campo (Es.: $content[body][#pre_render]) per chiamare una o più funzioni da eseguire per il particolare elemento. In questo caso è passato alla funzione il solo elemento $content[<campo>].
- Personalizzazione mediante $node->content['#post_render']
Dopo aver eseguito il rendering del contenuto, Drupal chiama tutte le funzioni eventualmente definite nell'array $node->content['#post_render']. Le funzioni possono avere un qualsiasi nome e ad esse Drupal passa la stringa $content contenente il rendering del contenuto e l'array $node->content.
- Personalizzazione mediante $node->content[<campo>]['#post_render']
Il valore [#post_render] può essere assegnato ad ogni campo (Es.: $content[body][#post_render]) per chiamare una o più funzioni da eseguire per il particolare elemento. Le funzioni possono avere un qualsiasi nome e ad esse Drupal passa la stringa $content contenente il rendering del contenuto e l'array $node->content[<campo>].
- Personalizzazione mediante ['#prefix'] e ['suffix']
Il rendering finale di ogni singolo elemento del contenuto viene sempre racchiuso tra i valori #prefix e #suffix forniti per quell'elemento come vediamo dal codice stesso della funzione drupal_render(&$elements)
<?php
function drupal_render(&$elements) {
......
$prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
$suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
return $prefix . $content . $suffix;
...
}
?>In questa fase, l'oggetto $node contiene il rendering del contenut , l'array dei links se presenti e quanto modificato o aggiunto dai moduli che implementano la funzione nomemodulo_nodeapi($node,'view', $teaser, $page).
Qui il nodo può essere ulteriormente modificato prima che sia applicato il tema corrente, implementando nei moduli la funzione nomemodulo_nodeapi($node,'alter', $teaser, $page).
Al nodo è applicata la tematizzazione mediante la funzionetheme('node', $node, $teaser, $page) . Generalmente per tematizzare un nodo viene usato il file template node.tpl.php. Di questo ne parleremo in altra parte.
Drupal durante le operazioni di caricamento, inserimento, aggiornamento, cancellazione e visualizzazione dei nodi , consente allo sviluppatore di eseguire funzioni personalizzate per alterare la modalità operativa standard.
Indichiamo con:
Per ogni tipo di operazione, la sequenza con cui sono descritte le funzioni coincide con quella di esecuzione.
Di seguito riportiamo le funzioni che , se esistenti, sono chiamate da Drupal nei diversi contesti.
Implementata nel modulo che gestisce il tipo di nodo, consente di caricare dei campi aggiuntivi all'oggetto nodo.
Consente a ogni modulo che la implementa di aggiungere ulteriori campi all'oggetto nodo non definiti nella tabella NODE.
Implementata nel modulo che gestisce il tipo di nodo, se presente sosituisce la funzione node_prepare() che è responsabile della generazione dell'array $node->[content].
Consente a ogni modulo che la implementa di preparare alla visualizzazione i campi aggiunti al nodo.
$type è il tipo di nodo (ad esempio 'node'),
Consente a ogni modulo che la implementa di aggiungere links da visualizzare nel nodo corrente.
Consente a ogni modulo che la implementa di modificare l'intero array dei links da visualizzare nel nodo corrente.
Consente a ogni modulo che la implementa di modificare l'intero oggetto $node prima che il nodo sia passato alla funzione theme('node', $node).
Gli argomenti trattati fanno riferimento alla versione 6.x di Drupal
Fanno parte dei blocchi, oltre ai blocchi stessi, anche i menu, i commenti, gli utenti, le categorie etc.
Tutti i blocchi condividono la tabella BLOCKS su cui il sistema salva informazioni di carattere generale. I contenuti sono invece salvati in tabella specifiche per ciascun tipologia di blocco.
Riporto, per comodità, le principali funzioni che sono implicate nel processo di lettura e visualizzazione del contenuto dei blocchi.
- template_preprocess_page(&$variables)
La funzione template_preprocess_page(), contenuta in includes/theme.inc, viene chiamata da theme('page') ed è la funzione che avvia il processo di lettura dei blocchi utilizzando le successive funzioni.
- theme_blocks($region)
La funzione theme_blocks($region) legge tuttii blocchi da visualizzare e contenuti nella regione identificata da $region.
Torna una stringa stampabile su web contenente tutto il codice HTML della regione richiesta.
Il contenuto della regione è inserito in $variables[$region] per essere utilizzato da page.tpl.php.
Le regioni generalmente sono:$left,$right,$header,$footer,$content.
- theme_block('view',$block)
La funzione theme_block('view',$block) formatta il contenuto $block->content chiamando il file template block.tpl.php. Può essere creata una funzione utente definendo la miotema_block() o phptemplate_block().
Torna una stringa stampabile su web contenente il codice HTML del contenuto $block->content.
- block_list($region)
La funzione block_list($region) legge le informazioni ed il contenuto dei blocchi da visualizzare nella pagina richiesta e nella regione identificata da $region.
Torna un oggetto $block per ogni blocco letto. Questo oggetto è utilizzato dal file template block.tpl.php.
Quando viene richiesta la visualizzazione di una qualsiasi pagina, Drupal carica per prima cosa il file index.php. All'interno di questo file viene chiamata la funzione theme() a cui è passato il paramentro 'page' . Con questo parametro la funzione theme() chiamerà la funzione template_preprocess_page.
All'interno di essa è contenuto il seguente codice:
<?php
............................................
global
$theme;
// Populate all block regions.
$regions = system_region_list($theme);
// Load all region content assigned via blocks.
foreach (array_keys($regions) as $region) {
// Prevent left and right regions from rendering blocks
when 'show_blocks' == FALSE.
if (!(!$variables['show_blocks']
&& ($region == 'left' || $region == 'right'))) {
$blocks = theme('blocks', $region);
}
else {
$blocks = '';
}
// Assign region to a region variable.
isset($variables[$region])
? $variables[$region] .= $blocks
: $variables[$region] = $blocks;
}
.........................
?>La system_region_list legge le regioni del tema corrente e, nel successivo cilclo, per ciascuna di esse, la funzione theme('blocks', $region) legge il contenuto dei blocchi appartenenti alla regione indicata e lo pone nella variabile $variables[$region] che sarà successivamente utilizzata dal file template del tema: page.tpl.php.
Sappiamo che chiamare la funzione theme('blocks', $region) equivale a chiamare la funzione theme_blocks($region) implementata nel modulo includes/theme.inc e di seguito riportata.
<?php
function theme_blocks($region) {
$output = '';
if (
$list = block_list($region)) {
foreach (
$list as $key => $block) {
// $key == <i>module</i>_<i>delta</i>
$output .= theme('block', $block);
}
}
?>In theme_blocks() sono presenti le due funzioni responsabili della lettura e visualizzazione dei blocchi:
La prima estrae dal database i contenuti da visualizzare insieme ad altre informazioni relative ai blocchi.
La seconda incapsula il contenuto ($block->content) in codice HTML secondo quanto definito nei file di template del tema corrente block.tpl.php o in altri definiti dall'utente.
Il contenuto dei blocchi da visualizzare sulla pagina è individuato all'interno della funzione block_list() mediante l'esecuzione della seguente query di selezione:
SELECT DISTINCT b.* FROM blocks b
LEFT JOIN blocks_roles r ON b.module = r.module AND b.delta = r.delta
WHERE b.theme = '<nome tema corrente>'
AND b.status = 1
AND (r.rid IN ( <elenco dei ruoli dell'utente corrente> ) OR r.rid IS NULL)
ORDER BY b.region, b.weight, b.moduleDa questa query vediamo che un blocco per essere selezionato deve:
Da quanto detto si capisce perchè, cambiando tema o utente certe volte non vengono visualizzati alcuni blocchi.
Abbiamo visto che la funzione block_list() è chiamata nel seguente modo: $list = block_list($region)
Il valore di ritorno $list è un array associativa i cui elementi sono così formati:
$block= $list["modulo_delta"] = oggetto
dove:
| $block->bid | da tabella BLOCKS |
| $block->module | da tabella BLOCKS |
| $block->delta | da tabella BLOCKS |
| $block->theme | da tabella BLOCKS |
| $block->status | da tabella BLOCKS |
| $block->weight | da tabella BLOCKS |
| $block->region | da tabella BLOCKS |
| $block->custom | da tabella BLOCKS |
| $block->throttle | da tabella BLOCKS |
| $block->visibility | da tabella BLOCKS |
| $block->pages | da tabella BLOCKS |
| $block->title | da tabella BLOCKS |
| $block->cache | da tabella BLOCKS |
| $block->content | contenuto del blocco (per un blocco , il contenuto di body) |
| $block->subject | titolo da visualizzare nella pagina |
| $block->enabled | VERO/FALSO (indica se il blocco è abilitato ad essere visualizzato) |
| $block->page_match | VERO/FALSO (indica se il blocco può essere visualizzato) |
Queste informazioni sono disponibili in fase di lettura del file template block.tpl.php.
Le tabelle dei contenuti
L'oggetto precedente contiene il valore $block->content che rappresenta il vero contenuto del blocco, ciò che è stato effettivamente inserito come informazione del blocco.
Questa informazione non è contenuta nella tabella BLOCKS ma nelle tabelle relative alla tipologia del blocco.
Ad esempio, per i principali moduli:
Per moduli non di sistema, potranno esserci altre tabelle di contenuto.
Le funzioni di lettura dei contenuti
Il contenuto del blocco è letto dalla funzione di gestione del modulo: nomemodulo_block().
La funzione di lettura dei contenuti del blocco è chiamata all'interno di block_list() mediante la funzione:
module_invoke($block->module, 'block', 'view', $block->delta).
Per i blocchi precedentemente indicati, il contenuto sarà letto da:
In generale , per moduli non di sistema , Drupal chiamerà la funzione nomemodulo_block('view', $blocks).
Gli argomenti trattati fanno riferimento alla versione 6.x di Drupal
I menu sono un particolare tipo di blocco.
La loro gestione è fornita dal modulo modules/menu.module e dalle funzioni contenute nel file includes/menu.inc.
menu_block($op = 'list', $delta = 0)
La funzione menu_block() legge il contenuto del menu individuato dal valore $delta. E' chiamata in fase di generazione dei blocchi dalla funzione block_list() con $op='view'.
Torna la seguente array:
$block['subject'] = titolo del bloccco
$block['content'] = stringa del contenuto del menu in formato HTML. [vedi menu_tree()]
L'array è usata in block.tpl.php.
menu_tree($delta)
La funzione menu_tree() ,chiamata da menu_block(), genera il codice HTML del menu individuato dal valore $delta.
Il valore di ritorno è una stringa.
Questa funzione chiama la menu_tree_page_data() per la lettura del contenuto del menu e la menu_tree_output() per la generazione del contenuto in codice HTML.
menu_tree_page_data($menu_name)
La funzione menu_tree_page_data() legge i contenuti dalle tabelle MENU_LINKS e MENU_ROUTER.
Ttornando un array associativa.
Vedere Il contenuto dei menu per una descrizione più dettagliata.
menu_tree_output($tree)
La funzione menu_tree_output() prende in ingresso l'array $tree prodotto da menu_tree_page_data() contenente tutte le informazioni sul menu da visualizzare e la converte in codice HTML .
Torna una stringa.
Questa funzione chiama le funzioni personalizzabili:
menu_primary_links()
La funziome menu_primary_links() torna un array $tree contenente titolo e riferimenti del menu di navigazione Primary links.
menu_secondary_links()
La funziome menu_secondary_links() torna un array $tree contenente titolo e riferimenti del menu di navigazione Secondary links.
theme_links($links,$attributes)
La funzione theme_links() genera il codice HTML dei menu di navigazione Primary links e Secondary links.
E' chiamata in page.tpl.php
menu_list_system_menus()
La funzione menu_list_system_menus() torna un array con i nomi dei menu di sistema:''navigation', 'primary-links', 'secondary-links';
menu_get_menus()
La funzione menu_get_menus() legge i nomi dei menu utente e di sistema dalla tabella MENU_CUSTOM.
Torna un array associativo con i nomi dei menu.
Esempio:
$menu[menu-mio] = "Menu mio"
$menu[navigation] = "Navigation"
$menu[primary-links] = "Primary links"
$menu[secondary-links] = "Secondary links"
menu_get_item($path=NULL, $router_item = NULL)
La funzione menu_get_item() legge i record dalla tabella MENU_ROUTER filtrando suii valori del campo "path" compatibili al percorso della pagina richiesta.
Ad esempio se il percorso della pagina richiesta è node/12345/edit, i possibili valori su cui sarà eseguito il filtro saranno:
7 node/12345/edit
6 node/12345/%
5 node/%/edit
4 node/%/%
3 node/12345
2 node/%
1 node
La funzione torna il primo record di MENU_ROUTER in cui il campo "path" è uguale ad uno dei valori suddetti.
La ricerca del valore di "path" che soddisfa ad uno dei valori suddetti è eseguita secondo il numero d'ordine discendente definito nel campo "FIT".
Abbiamo detto che un menu è un particolare tipo di blocco. Questo significa che le informazioni di selezione sono contenute nella tabella BLOCKS e seguono gli stessi criteri descritti per i blocchi. Quindi i menu selezionati saranno quelli che nella query di selezione dei blocchi hanno il nome modulo uguale a "menu".
Questo è vero per i menu generici.Per i menu primary-links e secondary-links la selezione avviene mediante le due funzion menu_primary_links() e menu_secondary_links() chiamate in template_preprocess_page() durante la generazione della pagina.
Rispetto ai blocchi, nei menu ciò che cambia è come leggere e visualizzare il contenuto e questo verrà descritto qui di seguito.
Il conenuto di un menu è letto dalla funzione menu_block(). All'interno di essa, la lettura e codifica del contenuto del menu viene eseguita, attraverso la funzione menu_tree($menu_name) , dalle due funzioni: menu_tree_page_data() e menu_tree_output().
- La prima , prende in input un nome di menu e in output fornisce un array ($tree) contenente tutte le informazioni lette dalle tabelle MENU_LINKS e MENU_ROUTER per il menu richiesto.
- La seconda, prende in input l'array $tree e genera in output il codice HTML del menu richiesto passandolo alla funzione menu_block().
<?php
function menu_tree($menu_name = 'navigation') {
static $menu_output = array();
if (!isset(
$menu_output[$menu_name])) {
$tree = menu_tree_page_data($menu_name);
$menu_output[$menu_name] = menu_tree_output($tree);
}
return $menu_output[$menu_name];
}
?>L'array $tree, contiene quindi tutte le informazioni delle singole voci appartenenti all'albero del menu corrente.
La singola voce del menu è individuata da una stringa costruita nel seguente modo:
$tree[<50000 + campo_weight> spazio <campo_title> spazio <campo_mlid>]
dove:
50000 è un valore fisso;
<campo_weight> è il peso (ordine) della voce nel menu;
<campo_title> è il titolo della voce corrente;
<campo_mlid> è l'identificativo univoco della voce in MENU_LINKS
Ad esempio per weight=-10 , title=Drupal mlid=96 la stringa che individua la voce è: $tree["49990 Drupal 96"]
Tutti i valori estratti per la singola voce del menu sono posti in $tree["49990 Drupal 96"][link].
Qui di seguito sono riportati i valori contenuti in $tree per ogni voce del menu:
(MR = da tabella MENU_ROUTER; ML= da tabella MENU_LINKS; AL=da altre fonti ) MR $tree[ 49990 Drupal 96][link][load_functions] MR $tree[ 49990 Drupal 96][link][to_arg_functions] MR $tree[ 49990 Drupal 96][link][access_callback] MR $tree[ 49990 Drupal 96][link][access_arguments] MR $tree[ 49990 Drupal 96][link][page_callback] MR $tree[ 49990 Drupal 96][link][page_arguments] MR $tree[ 49990 Drupal 96][link][title] = Drupal MR $tree[ 49990 Drupal 96][link][title_callback] MR $tree[ 49990 Drupal 96][link][type] MR $tree[ 49990 Drupal 96][link][description] ML $tree[ 49990 Drupal 96][link][menu_name] ML $tree[ 49990 Drupal 96][link][mlid] = 96 ML $tree[ 49990 Drupal 96][link][plid] ML $tree[ 49990 Drupal 96][link][link_path] = node/67 ML $tree[ 49990 Drupal 96][link][options] => array() ML $tree[ 49990 Drupal 96][link][module] ML $tree[ 49990 Drupal 96][link][hidden] ML $tree[ 49990 Drupal 96][link][has_children] ML $tree[ 49990 Drupal 96][link][expanded ] ML $tree[ 49990 Drupal 96][link][weight ] = -10 ML $tree[ 49990 Drupal 96][link][depth] ML $tree[ 49990 Drupal 96][link][customized] ML $tree[ 49990 Drupal 96][link][p1] = 96 ML $tree[ 49990 Drupal 96][link][p2] ML $tree[ 49990 Drupal 96][link][p3] ML $tree[ 49990 Drupal 96][link][p4] ML $tree[ 49990 Drupal 96][link][p5] ML $tree[ 49990 Drupal 96][link][p6] ML $tree[ 49990 Drupal 96][link][p7] ML $tree[ 49990 Drupal 96][link][p8] ML $tree[ 49990 Drupal 96][link][p9] ML $tree[ 49990 Drupal 96][link][updated ] AL $tree[ 49990 Drupal 96][link][in_active_trail] = FALSO/VERO AL $tree[ 49990 Drupal 96][link][access ] = VERO/FALSO AL $tree[ 49990 Drupal 96][link][href ] = node/67 AL $tree[ 49990 Drupal 96][link][localized_options] = array() AL $tree[ 49990 Drupal 96][link][below] = FALSO/VERO
Le prime componenti riguardano le funzioni e gli argomenti richiesti per visualizzare la voce del menu.
Poi ci sono alcune voci interessanti: il nome del menu [menu_name], se la voce è espansa o no [expanded], se ha figli [has_children], la pagina a cui punta [href ], il livello di profondità a cui appartiene la voce [depth], se la voce è quella selezionata [in_active_trail]. La componente [localized_options] può contenere un array caricato da funzioni di tematizzazione. Ad esempio la funzione theme_menu_item_link() la usa per inserite gli attributi per il tag HTML <a>.
Avendo il menu una struttura ad albero , l' eventuale identificativo della voce padre è posto in [plid], ed inoltre, per ogni ramo, sono indicati i nodi di diramazione <mlid> fino al nodo radice , attraverso i valori da [p1] (radice) a [p9].
Infine il valore [below] può contenere un array. Questa array è ancora di tipo $tree e rappresenta tutto il sotto albero che si sviluppa a partire dalla voce corrente.
Le due funzioni preposte alla lettura dei menu di navigazione sono la menu_primary_links() e menu_secondary_links(), chiamate all'interno della funzione template_preprocess_page(). Il codice HTML dei menu generato viene posto in $variables['primary_links'] e $variables['secondary_links'], per essere infine reso disponibile nel template page.tpl.php mediante le variabili $primary_links e $secondary_links.
Dalla funzione menu_primary_links() torna un array $links[] ad esempio formato nel seguente modo:
$links[menu-45 active-trail][] = array() eventuali attibuti $links[menu-45 active-trail][href] => node/18 $links[menu-45 active-trail][title] => LINK_1 $links[menu-48][] = array() eventuali attibuti $links[menu-48][href] => node/19 $links[menu-48][title] => LINK_2 $links[menu-46l][] = array() eventuali attibuti $links[menu-46][href] => node/17 $links[menu-46][title] => LINK_3
Nell'esempio il menu è formato da:
Questa array viene successivamente elaborata dalla funzione theme_links($primary_links,array('class' => 'links primary-links') ), chiamata nel file template page.tpl.php (tema garland), e che produce il codice HTML definitivo:.
<ul class="links primary-links"> <li class="first menu-45 active-trail"> <a href="/node/18" class="active">LINK1</a> </li> <li class="menu-48"> <a href="/node/19">LINK_2</a> </li> <li class="menu-46"> <a href="/node/17">LINK_3</a> </li> </ul>
Per la precisione in page.tpl.php viene chiamata la funzione theme('links',$primary_links,array('class' => 'links primary-links')) ma che sappiamo corrispondere alla theme_links(). Questa funzione peraltro può essere personalizzata generando in template.php la funzione miotema_links() o phptemplate_links().
Il codice generato , è infine incapsulato in page.tpl.php all'interno di un blocco <DIV> nel seguente modo:
<div class="links primary-links" >
codice HTML prodotto
</div>
Di seguito è riportato il codice della funzione theme_links() fornita con Drupal .
All'interno dell codice sono riportati alcuni commenti esplicativi.
<?php
// Parametri in ingresso
// $links contiene l'array prodotto da menu_primary_links()
// $attibutes è un array che conterrà il valore passato in page.tpl.php, in paticolare per il tema garland viene passata il // valore array('class' => 'links primary-links')
function theme_links($links, $attributes = array('class' => 'links')) {
$output = '';
// Qui vengono contati il numero di link del menu per definire la class 'first' e 'last'
if (count($links) > 0) {
// Inizio della lista con TAG <ul> l'attributo ID del tag corrisponde al valore 'class' passato in input
$output = '<ul'. drupal_attributes($attributes) .'>';
$num_links = count($links);
$i = 1;
// Inizio lettura LINK
foreach ($links as $key => $link) {
// Definizione dell' attributo 'class' per il tag <li>
// Il nome minimo sarà menu-xx. nel nostro esempio menu-45 menu-46 menu-48
$class = $key;
// Aggiunge 'first', 'last' e 'active' alla stringa della classe per meglio specificare l'elemento che si sta visualizzando.
if ($i == 1) {
$class .= ' first';
}
if ($i == $num_links) {
$class .= ' last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
$class .= ' active';
}
// Scittura del tag <li>
$output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
// preparazione del tag anchor <a>
if (isset($link['href'])) {
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
}
else if (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
}
// fine primo link
$i++;
$output .= "</li>\n";
}
// fine lista
$output .= '</ul>';
}
// torna il codice prodotto
return $output;
}
?>Quanto detto per il menu Primary links vale per Il menu Secondary links.
E' utilizzata per la lettura dei contenuti la funzione: menu_secondary_links().
In page.tpl.php la variabile usata è la $secondary_links.
Il blocco <div> che coniene il codice HTML è il seguente:
<div class="links secondary-links" >
codice HTML prodotto
</div> Un tema identifica tutto ciò che consente di visualizzare i contenuti del sito secondo una rappresentazione grafica definita dal tema stesso. I contenuti del sito sono quindi sempre gli stessi ma posizionati e visualizzati in modo diverso in funzione del tema scelto.
In generale un tema è costituito dai seguenti elementi:
Le regioni
Le regioni indicano come i diversi conenuti da visualizzare sulla pagina devono essere posizionati.
In pratica rappresentano lo scheletro della pagina, una serie di buchi da riempire con contenuti.
La struttura maggiormente usata per le regioni è la seguente:
Una intestazione (header), una o due barre laterali a sinistra e a destra (sidebar) per blocchi, menu, pubblicità, una regione centrale (content) contenente il contenuto principale della pagina e una regione a fondo pagina (footer) per informazioni secondarie del sito. Nulla vieta naturalmente di complicare la pagina definendo più regioni.
I fogli di stile CSS
Uno o più file contenenti le definizioni degli stili da applicare ai tag HTML del tema.
Il file principale per definizione è il file style.css
I file template
Sono i file che applicano il codice HTML ai contenuti da visualizzare. Questi file hanno sempre
estensione .tpl.php
I temi di Drupal hanno quattro file template fondamentali che si trovano sempre nella directory del tema.
Il file template.tpl.php
In questo file possono essere implementate funzioni che consentono di eseguire un override delle funzioni di base della tematizzazione.
Ad esempio il codice HTML per i link che compaiono sotto un nodo quando è mostrato in modalità sommario (teaser) come leggi tutto, aggiungi un commento etc, è definito nella funzione di base theme_links(). Volendo visualizzare in modo diverso questi link si potrà definire la funzione miotema_links() nel file template.tpl.php. Drupal trovando questa nuova funzione, la eseguirà al posto della theme_link().
Immagini e icone
Immagini e icone di corredo al tema.
QUESTA SEZIONE E' IN LAVORAZIONE
----------------------------------------------
Quando Drupal deve generare il codice HTML per elementi come nodi, blocchi , menu, breadcrumb, links e altro, cerca, per il tema corrente, le funzioni e file teplate che consentono di codificare gli elementi richiesti.
La ricerca avviene applicando regole sulla priorità di ricerca, sui nomi e sulla posizione delle funzioni e dei file all'interno delle directory e dei moduli che consentono a Drupal di ottenere una elevata personalizzazione del sistema.
Conoscendo e seguendo le regole di ricerca è possibile personalizzare un sito generando nuove funzioni e file template in base alle proprie esigenze.
Nome del tema
Il nome del tema deve essere diverso dal nome di qualsiasi modulo
Directory del tema
Tutti i file appartenenti alla definizione di un tema , devono stare all’interno di una propria subdirectory che prende il nome del tema. La subdirecotory può essere contenuta all'interno di una delle seguente directory:
Il motore di elaborazione del tema controllerà , per il tema selezionato, la presenza di file template con estensione .tpl.php.
Il file screenshot del tema
Il file deve essere in formato .png di dimensioni 150x90.
Se presente viene mostrato nella pagina di amministrazione dei temi.
Il file di stile del tema
Il tema utilizza come dichiaratore di stile il file style.css per default.
Altri file possono essere caricati utilizzando l'istruzione @import dei file css.
Temi multipli con più file di stile
E’ possibile creare temi che differiscono per il solo file di definizione degli stili css:style.css.
Per fare questo bisogna creare nella directory di base del tema, delle subdirectory contenenti i file style.css. Ogni subdirectory costituirà un nuovo tema. Ad Esempio:
miosito/sites/all/themes/miotema_A/ (directory principale del tema)
Il motore riconoscerà tre temi: miotema_A, miotema_B, miotema_C.
Ciascun tema utilizzerà i file di base con estensione .tpl.php, e ciascuno avrà nella propria subdirectory il file di stile style.css.
Gli argomenti trattati fanno riferimento alla versione 5.x di Drupal
Funzioni principali:
phptemplate_regions()
drupal_set_content($region=NULL,$data=NULL)
I temi possono definire ed implementare un numero generico di regioni.
Le regioni sono essenzialmente contenitori di... contenuti.
Le regioni suddividono la pagina del browser in aree che costituiranno i limiti in cui visualizzare i contenuti stessi. Così, generalmente, tutti i temi hanno una regione per:
ed altre regioni che possono complicare notevolmente il layout del sito.
Definizione delle regioni
Le regioni sono definite mediante una funzione php che torna un array associativo contenente la codifica delle regioni e la loro descrizione utilizzata nella pagina di amministrazione dei blocchi.
La funzione è la seguente:
function phptemplate_regions() {
return array(
'left' => t('left sidebar'),
'right' => t('right sidebar'),
'content' => t('content'),
'header' => t('header'),
'footer' => t('footer')
);
}Il primo nome della regione diventa la regione di default per il posizionamento di blocchi nel caso in cui non sia dichiarata espressamente una regione.
Nel caso di PhpTemplate Engine la funzione phptemplate_regions() è contenuta nel file: miosito/themes/engines/phptemplate/phptemplate.engine.
Drupal prima di chiamare questa funzione , verifica se esiste una funzione analoga fornita nei file template del tema corrente e che si chiami miotema_regions().
Per cui, per personalizzare le regioni di un tema, bisogna definire la funzione miotema_regions() nel file template.php nella directory del tema.
function miotema_regions() {
return array(
'regione1' => t('regione1'),
'regione2' => t('regione2'),
'regione3' => t('regione3'),
'header' => t('header'),
'footer' => t('footer')
);Nel caso di .theme Engine la funzione è contenuta nel file del tema miotema.theme
Per riempire una regione è possibile utilizzare la funzione
function drupal_set_content($region = NULL, $data = NULL) {
static $content = array();
if (!is_null($region) && !is_null($data)) {
$content[$region][] = $data;
}
return $content;
}Es.: drupal_set_content('left', 'Hello there.')
Gli argomenti trattati fanno riferimento alla versione 5.x di Drupal
Il motore phptemplate è contenuto nella direcotory themes/engines/phptemplate ed è costituito dai seguenti file:
1) phptemplate.engine contenente le funzioni di default per la gestione di blocchi, box. commenti, nodi
2) default.tpl.php non è ancora chiaro l'uso
3) node.tpl.php per la stampa dell’oggetto nodo
4) block.tpl.php per la stampa dell’oggetto blocco
5) box.tpl.php per la stampa dell’oggetto box
6) comment.tpl.php per la stampa dell’oggetto commento
Questi sono alcuni dei file necessari per la gestione di un tema di default. Ma per la realizzazione del tema sono necessari altri due file,fondamentali, contenuti obbligatoriamente nella subdirectory del tema selezionato:
page.tpl.php è il file principale del tema che definisce il layout del tema.
style.css contiene la definizione degli stili del tema.
Ogni tema può quindi utilizzare, i due file page.tpl.php e style.css pi ù i cinque file di default .tpl.php contenuti in themes/engines/phptemplate oppure una loro implementazione personalizzata. In questo caso i file si dovranno chiamare allo stesso modo , ma dovranno trovarsi nella subdirectory del tema.
Aggiungere un tema
Per aggiungere un nuovo tema, si deve quindi:
creare una nuova directory con il nome del tema in /sites/all/themes/miotema oppure /themes/miotema
La cosa più semplice, comunque, è prendere i file di un tema esistente, magari di quelli di default (bluemarine), copiarli nella nuova directory e cominciare a modificarli secondo le proprie esigenze.
I blocchi sono costituiti da codice HTML , eventualmente costruito dinamicamente da script PHP, posizionato all’interno di una regione del tema corrente. Esempi di un blocco sono i campi utente/password per il login al sistema, il menu di navigazione e in generale i menu utente, il calendario etc.
Un blocco può anche essere costituito da una singola stringa, immagine o altro da posizionare in una determinata regione del tema.
Per definire un blocco si hanno due possibilità:
Aggiunta da interfaccia di un nuovo blocco utente
In questa modalità un utente con permessi di amministrazione dei blocchi, può creare un nuovo blocco. Basta andare nella pagina di amministrazione dei blocchi ed eseguire Aggiungi blocco.
Impostare un titolo e nell’area Corpo del blocco definire il codice HTML o PHP del nuovo blocco.
Esempio.:
<p>questo è un blocco </p> oppure <?php print “questo è un blocco”; ?>
Attenzione, selezionare l’opzione appropriata per il formato di input.
Blocco che contiene un altro blocco
Un blocco può anche contenere, a sua volta, un altro blocco.
Per richiamare un blocco utente scrivere:
<?php
$block = module_invoke('block', 'block', 'view', 1);
print $block['content'];
?>
Dove il valore 1 indica il delta , ma per i blocchi utenti rappresenta il primo blocco creato, 2 il secondo blocco creato etc. etc. Questo valore può essere letto nella tabella blocks di MySQL nel campo delta.
Il codice scritto dall’utente &erave; invece contenuto nella tabella boxes nel campo body mettendo in join i campi boxes.bid = blocks.delta.
Definizione di un modulo
Per definire un blocco all’interno di un modulo Drupal, è necessario implementare la funzione nomemodulo_block() all’interno del modulo. Questo esula dalla presente documentazione e si rimanda l’argomento alla trattazione dei moduli.
Posizionamento di un blocco
Tutti i blocchi definiti sono visibili nella pagina di amministrazione dei blocchi, da cui è possibile indicare in quale regione visualizzare il blocco.
Template del tema corrente per la visualizzazione del contenuto di un nodo.
E' usato nella fase di preparazione del codice HTML per il contenuto della pagina richiesta, preparazione avviata dalla funzione menu_execute_active_handler()
E' sconsigliato inserire direttamente codice HTML in Drupal, sebbene sia permesso dai formati di input (FilteredHTML,FullHTML). Drupal mette a disposizione delle funzioni proprio per produrre codice HTML personalizzabili all'interno di ciascun tema.
Le funzioni che producono codice HTML, devono però poter funzionare per qualunque tema selezionato. Ad esempio volendo stampare una tabella si può usare la funzione theme_table() o volendo stampare un blocco si può usare la funzione theme_block(). Tutte le funzioni tematizzate di sistema si trovano nel file includes/theme.inc. Ma se, ad esempio, un tema deve visualizzare l’oggetto ‘blocco’ in un modo particolare può essere implementata la funzione theme_block(), chiamandola miotema_block(), ed inserendola nel file template.tpl.php.
A questo punto è necessario che Drupal sia in grado di sapere che esiste una funzione personalizzata ed usare quella invece della funzione di default. Prendondo come esempio la funzione theme_table(), Drupal, nel momento in cui deve chiamare la funzione, verifica, con le priorità indicate, se:
Il tema implementa la funzione
Verifica se la funzione theme_table() è implementata nel tema corrente.
La funzione implementata:
Il motore di template implementa la funzione
Se il tema non implementa la funziona, Drupal verifica se la funzione theme_table() è implementata dal motore di template del tema corrente.
La funzione implementata:
Il sistema implementa la funzione
Se il motore non implementa la funziona, Drupal chiama la funzione theme_table() implementata da sistema.
La funzione implementata:
Un help delle funzioni di sistema tematizzate può essere trovato in http://api.drupal.org/api/group/themeable/5?sort=asc&order=Name
La funzione theme()
Quando abbiamo bisogno di chiamare una funzione tematizzata, è bene non chiamare la funzione direttamente, ma lasciare che sia Drupal a fare questo per noi tramite la funzione theme('block',args). Infatti supponiamo di voler visualizzare una tabella all'interno di codice php scritto da noi, la chiamata alla funzione giusta potrebbe essere del tipo:
function miafunzione() {
......
// stampa tabella
if (isset('miotema_table') miotema_table(.....);
elseif (isset('phptemplate_table') phptemplate_table(.....);
else theme_table();
......
}Tutto questo può essere semplificato utilizzando la funzione theme() e delegare a Drupal la scelta della funzione corretta:
function miafunzione() {
......
// stampa tabella
theme('table',$args);
......
} Abbiamo visto come l'applicazione di un tema agli elementi del sito , venga eseguito da Drupal mediante funzioni come theme_breadcrumb($breadcrumb), theme_links($links, $attributes) o mediante file template come page.tpl.php, node.tpl.php, block.tpl.php. Per tenere traccia di queste e delle altre informazioni necessarie per applicare correttamente un tema agli elementi del sito, Drupal genera il cosiddetto theme registry. Fisicamente il tema registry è costituito da un'array associativa , indicata in seguito come $hooks, contenente tutti i nomi dei possibili hooks (breadcrumb,links,block,node,page) e, per ciascuno di essi, le corrette informazioni per gestire quella tipologia di elemento.L'array generato è salvato nel database. L'individuazione della funzione o del file template da utilizzare avviene passando sempre attraverso la funzione che è alla base della tematizzazione di Drupal: theme($hook,$args). Il parametro $hook indica a quale elemento applicare il tema. Ad esempio theme('breadcrumb',$args) per il breadcrumb, theme('links',$args) per i links del nodo, theme('node',$args) per un nodo, theme('page', $args) per la pagina finale.
Il valore $args indica qui semplicemente il passaggio di uno o più argomenti alla funzione theme().
Infatti come si vede dal frammento di codice della funzione theme
<?php
function theme() {
$args = func_get_args();
$hook = array_shift($args);
static
$hooks = NULL;
if (!isset($hooks)) {
init_theme();
$hooks = theme_get_registry();
}
.....
$info = $hooks[$hook];
.....
}
?>i parametri non sono passati esplicitamente , ma sono letti mediante la funzione func_get_args().
In questo modo possono essere passati un numero di argomenti indefinito che la funzione theme() passerà alla funzione o al file template che effettivamente si occuperà di tematizzare l'elemento.
Il primo parametro è sempre il valore hook che viene estratto dall'array $args.
Dopo aver letto gli argomenti e individuato l'hook, Drupal carica l'array $hooks dal database. La lettura dell'array è eseguita la prima volta che viene chiamata la funzione theme() mediante la funzione theme_get_registry(). Successive chiamate di theme() troveranno l'array $hooks carico in quanto definito come variabile 'static'.
Da dove è letto il theme registry?
Il theme registry è generato ogni volta che si entra nella pagina contenente la lista dei moduli. Dopo averlo generato Drupal salva l'array nel database e precisamente nella tabella CACHE.
In questa tabella, ogni tema ha un suo theme registry salvato nel campo DATA , e individuato dal record con il campo CID uguale a "theme_registry:NomeTema", dove NomeTema è ovviamente il nome del tema. Volendo quindi forzare la rigenerazione del theme registry basterà semplicemente cancellare il record associato al tema.
L'array $hooks
L'array $hooks è un array associativo nella forma $hooks['hook'][propietàX] = valore , dove valore può essere anche un array o un oggetto. Poco più avanti nel frammento di codice, Drupal per comodità, carica in $info le sole informazioni relative all'hook corrente:$hooks[$hook].
Come viene costruita l'array $hooks? Da dove Drupal prende le informazioni in essa contenute?
Vediamo in dettaglio la costruzione dell'array, supponendo di voler generare il theme registry per il tema Minnelli derivato dal tema Garland e gestito dal motore phptemplate.
Entrando in theme(), Drupal verifica l'esistenza della variabile statica $hooks e se non ancora impostata,
avvia l'inizializzazione del tema corrente tramite la init_theme().
Il tema corrente è definito o in $user->theme o , se nullo, con il tema di default letto con la funzione variable_get('theme_default', 'garland').
Tra le operazione attivate durante l'inizializzazione del tema, quella che a noi qui interessa è la creazione del theme registry. Per leggere gli hooks, Drupal usa la funzione _theme_load_registry() definita in theme.inc, che verifica l'esistenza del theme registry nella tabella CACHE e in caso affermativo riporta l'array contenuto nel campo DATA, altrimenti avvia la sua costruzione.
Nel secondo caso, Drupal dovrà quindi individuare tutti gli hooks e le loro proprietà definiti all'interno del sistema.
La costruzione del theme registry avviene in due fasi:
a) Individuazione di tutti gli hooks definiti nel sistema;
b) Modifica dei parametri degli hooks letti mediante ricerca di funzioni e/o file template personalizzate.
La funzione che avvia la costruzione del theme registry è la funzione _theme_build_registry($theme, $base_theme, $theme_engine) in cui i parametri indicano il nome del tema, il tema base di riferimento (nullo se il tema è già un tema base) , il nome del motore di gestione del tema, nel nostro caso phptemplate.
Gli hooks appartenenti al theme registry sono definiti all'interno dei moduli.
Ogni modulo che vuole esporre i propri hooks deve implementare la funzione nomemodulo_theme() che deve fornire un'array contenente nomi e proprietà degli hooks da esporre.
Ad esempio il modulo di gestione dei blocchi, implementa la funzione block_theme():
<?php
function block_theme() {
return array(
'block_admin_display_form' => array(
'template' => 'block-admin-display-form',
'file' => 'block.admin.inc',
'arguments' => array('form' => NULL),
),
);
}
?>che espone il solo hook "block_admin_display_form" e indicando che deve essere gestito tramite file template. Dove starà il file template? Se non altrimenti definito Drupal si aspetta di trovarlo nel percorso del modulo. Altri esempi è possibile vederli in node_theme() nel modulo node.module, in comment_theme() nel modulo comment.module etc. Per individuare tutti gli hooks dei moduli Drupal esegue un ciclo su tutti i moduli attivi chiamando per ogni modulo la funzione: _theme_process_registry(&$cache, $name, $type, $theme, $path)
dove:
La funzione _theme_process_registry legge l'array restituito dalla funzione nomemodulo_theme() e aggiunge al theme registry gli hook in essa definiti.
Di seguito indichiamo con $info[] l'array restituito dalla funzione nomemodulo_theme() per un singolo hook.
Per l'esempio precedente si avrebbe:
$info[template]= 'block-admin-display-form'
$info[file]= 'block.admin.inc
$info[arguments]=array('form' => NULL)
e con $hook[] le proprietà generate nel theme registry per l'hook letto, ad esempio per block_admin_display_form .
Ad ogni hooks Drupal assegna le seguenti proprietà:
$hook[type]
Valore sempre presente, definito da codice.
Indica dove l'hook è stato definito. Per i moduli è uguale a 'module'
$hook[theme path]
Indica il percorso del modulo. $hook[theme path]=$path (passato come argomento)
$hook[arguments]
Array.Indica il nome e il valore di default degli argomenti da fornire alla funzione o al file template.
E' il valore $info[arguments]
$hook[function]
Indica il nome della funzione di gestione dell'hook.
Se un modulo non definisce ne la proprietà "template" ne la proprietà "function" Drupal imposta
$hook[function]=theme_hook() come nome della funzione che dovrà gestire l'hook. Naturalmente la funzione theme_hook() deve essere implementata nel modulo.
$hook[file]
Se è impostata la proprietà $info[file] , significa che le funzioni di tematizzazione dell'hook sono definite nel file indicato, ad esempio nomemodulo.inc. La corrispondente proprietà dell'hook sarà:
$hook[file]=$path .'/'. $info['file'] con $path percorso del modulo.
E' possibile mettere le funzioni di gestione anche in file esterni alle directory del modulo , impostando la proprietà $info[path]. In questo caso il valore $hook[file] non viene impostato, ma è caricato immediatamente il file
$info['path'] .'/'. $info['file'] per individuare nelle successive fasi eventuali funzioni di tematizzazione.
$hook[template]
Solo se non definita la proprietà $info[function]
Indica il nome e percorso del file template.
Per default il file template viene definito nel percorso del modulo:
$hook[template] = $path ."\" . $info[template];
$hook[theme paths]
Array.Indica un array di directory in cui cercare eventuali implementazioni per il tema.
Per i moduli è aggiunto o la directory del modulo o la proprietà $info[path] se definita.
$hook[preprocess functions]
Array.Indica un array di funzioni di preprocessing da usare in caso di gestione con file template.
Se è definita l'array $info[preprocess functions] allora sarà $hook[preprocess functions]=$info[preprocess] altrimenti Drupal genera l'array $info[preprocess] avviando la ricerca in tutti i moduli delle seguenti funzioni:
e aggiungendo sempre la funzione template_preprocess definita in theme.inc e, se esistente, la funzione template_preprocess_hook
Al termine della ricerca sarà: $hook[preprocess functions]=$info[preprocess].
Terminato di impostare le proprietà di tutti gli hooks appartenenti al modulo, la funzione _theme_preprocess_registry aggiiungerà gli hooks inidividuati nel modulo corrente all'array generale degli hooks $cache.
Nella fase precedente, Drupal ha individuato tutti gli hook definiti nei moduli tramite le funzioni nomemodulo_theme(). Chi sviluppa un modulo deve fornire anche le funzioni o i file template associati agli hooks esposti in nomemodulo_theme(). Drupal consente però di eseguire un "override" delle funzioni e file template fornite mediante la ricerca di funzioni e template alternativi.
Per ogni hook definito Drupal cerca l'esistenza delle seguenti funzioni in ordine di priorità
- nometema_hook()
- nometemabase_hook()
- engine_hook()
e quindi continuando a suppore minnelli come tema corrente, garland come tema base e phptemplate come motore per i temi , Drupal cercherà le seguenti funzioni:
- minnelli_hook()
- garland_hook()
- phptemplate_hook()
Per i file template chercherà i seguenti file:
- hook.tpl.php nella directory del tema corrente (minnelli)
- hook.tpl.php nella directory del tema base (garland)
Per ogni funzione trovata Drupal imposta:
$hook['function]=<nuovo_nome_funzione>
Per ogni template trovato Drupal imposta:
$hook['template]=<file template>
$hook['path]=<directory del tema>
Infine Drupal modifica anche le seguenti proprietà:
$hook[type]
Il valore è posto uguale a 'base_theme_engine' se la ricerca avviene all'interno della directory
del tema base. E' posto uguale a 'theme_engine' se la ricerca avviene all'interno della directory
del tema corrente.
$hook[theme path]
Indica il percorso del tema.
$hook[theme paths]
Oltre ai paths già individuati, aggiunge il path del tema:
$hook[theme paths][]=$path
$hook[preprocess functions]
Drupal aggiorna la proprietà cercando le seguenti funzioni di preprocessing:
- phptemplate_engine_preprocess
- phptemplate_engine_preprocess_hook
- phptemplate_preprocess
- phptemplate_preprocess_hook
- nometemabase_preprocess
- nometemabase_preprocess_hook
- nometema_preprocess
- nometema_preprocess_hook
L'ultima possibilità di modificare il theme registry è data da Drupal mediante la funzione drupal_alter('theme_registry', $cache).
Questa funzione ricerca e chiama tutte le funzioni nomemodulo_themaregistry_alter($hooks) che possono quindi modificare ulteriormente le informazioni fornite precedentemente. Ad esempio un modulo che implementa funzioni tipo theme_hook() potrebbe utilizzare funzioni differenti in base al contesto in cui si trova.
Riepiloghiamo di seguito le principali funzioni utillizzate per la generazione del theme registry.
_theme_build_registry($theme, $base_theme, $theme_engine)
dove:
$theme è il nome del tema
$base_theme è il tema base di riferimento (nullo se il tema è già un tema base)
$theme_engine è il nome del motore di gestione del tema, nel nostro caso phptemplate.
Contenuta in includes/theme.inc
Questa funzione avvia il processo di costruzione del theme registry.
_theme_process_registry(&$cache, $name, $type, $theme, $path)
dove:
$cache è l'array degli hooks che si sta generando a cui accodare eventuali altri hooks
$name è il nome del modulo o del tema in cui cercare gli hooks
$type = indica il tipo di ricerca che si sta eseguendo. Assume i valori: module, base_theme_engine, base_theme, theme_engine, theme.
$theme nome del modulo o del tema
$path indica la directory del modulo
Definita in includes/theme.inc
E' chiamata cinque volte all'interno della funzione _theme_build_registry(), una per ogni tipologia di ricerca.
1) $type= module
$name e $theme corrispondono al nome del modulo
Ricerca delle definizioni degli hooks nei moduli.
Per eseguire la ricerca chiama le funzioni nomemodulo_theme()
2) $type= base_theme_engine
$name=motore del tema , nel nostro caso: phptemplate
$theme=nome del tema base su cui eseguire la ricerca (garland ad esempio)
$path=percorso del tema
Ricerca le funzioni personalizzate con nome phptemplate_hook() e nometemabase_hook()
Ricerca i template personalizzati nella directory del tema base (garland)
Per eseguire la ricerca chiama la funzione phptemplate_theme() definita in themes/engines/phptemplate
3) $type= base_theme
$name e $theme corrispondono al nome del tema base
$path=percorso del tema base
Per eseguire la ricerca chiama, se esiste, la funzione nometemabase_theme().
Questa funzione non è implementata in Drupal..
4) $type=theme_engine
$name=motore del tema , nel nostro caso: phptemplate
$theme=mode le tema su cui eseguire la ricerca (minnelli ad esempio)
$path=percorso del tema
Ricerca le funzioni personalizzate con nome phptemplate_hook() e nometema_hook()
Ricerca i template personalizzati nella directory del tema (minnelli)
Per eseguire la ricerca chiama la funzione phptemplate_theme() definita in themes/engines/phptemplate
5) $type=theme
$name e $theme corrispondono al nome del tema base
$path=percorso del tema
Per eseguire la ricerca chiama, se esiste, la funzione nometema_theme().
Questa funzione non è implementata in Drupal.
phptemplate_theme($existing, $type, $theme, $path)
dove:
$existing è l'array degli hooks definiti nel sistema
$type uguale a 'base_theme_engine' (ricerca per tema base ) o 'theme_engine' (ricerca per tema derivato)'
$theme è il nome del tema per cui cercare funzioni o template personalizzati
$path è il percorso del tema
Definita in themes/engines/phptemplate/pgptemplate.engine
Praticamente è la funzione che ricerca tutte le funzioni e i file template personalizzati, consentendo allo sviluppatore di eseguire l'override delle funzioni e template di default..
Drupal cerca i moduli da installare nelle directory e sottodirectory:
/modules contiene i moduli di sistema (core)
/sites/all contiene altro tra cui moduli propri.
E’ consigliato creare una sottodirectory per i moduli aggiuntivi.
/sites/all/modules
I file principali del modulo , che devono essere contenuti in /sites/all/modules/miomodulo si devono chiamare :
Un modulo può essere di tipo:
Block module
Sono moduli che generalmente vengono posizionati sulle barre laterali. Drupal chiama la funzione miomodulo_block($op=='view') con opzione uguale a view per ottenere il contenuto del blocco. In particolare Drupal si aspetta un array $block di ritorno con i seguenti valori impostati:
$block['subject'] = t('MioModulo');
$block['content'] = contenuto del blocco;
Node module
Sono moduli che generalmente generano pagine di contenuto come blog, forum, book pages.
Le funzioni minime che è bene definire per un modulo sono:
IN FASE DI REALIZZAZIONE
Elenco degli hook principali
Drupal chiama tutte le funzioni hook_exit() implementate nei moduli attivi, per avvisare che la pagina richiesta è stata inviata e che le operazioni da attivare sono terminate.
L' hook exit può essere utile per eseguire un debugging del sistema o aggiornare, in fase di chiusura della pagina, alcune tabelle associate ai moduli.
Due moduli di sistema che usano questo hook sono:
Drupal chiama tutte le funzioni hook_load() implementate nei moduli attivi, per aggiungere campi non predefiniti nell'oggetto nodo.
Ad esempio una rubrica telefonica può avere campi come indirizzo, telefono etc. con un modulo rubrica che implementa la funzione rubrica_load (&$nodo)
Premesso che , l’accesso ad un modulo viene impostato tramite la pagina Gestione utenti->Controlli accessi.
In questa pagina compaiono per ogni modulo i permessi associati ad esso e per ogni permesso a quale ruolo è assegnato il permesso.
I ruoli per default sono due: anonymous user e authenticated user.
E’ possibile aggiungere altri ruoli utilizzando la pagina Gestione utenti->Ruoli.
Detto questo, le descrizione dei permessi che compaiono nella pagina Gestione utenti->Controlli accessi sono definite mediante la funzione:
<?php
function miomodulo_perm()
{
return array(
"amministra contenuti miomodulo",
"crea contenuti miomodulo");,
}
?>Qui sopra sono riportati solo due permessi, ma ovviamente ne potrebbero essere definiti altri. E' bene inserire sempre il nome nel modulo per ogni permesso. In caso contrario Drupal potrebbe assegnare la stringa di permesso a più moduli, creando seri problemi all'impianto di sicurezza.
Per verificare se l’utente corrente ha determinati permessi usare la funzione user_access()
<?php
if (!user_access("amministra contenuti miomodulo")) {
$form['error'] = array('#type' => 'item',
'#title' => t("Non sei autorizzato ad accedere a miomodulo."));
return $form;
}
?>Versioni precedenti alla 5.0 di Drupal usavano la funzione message_access() ora deprecata.
Pagina dei moduli
Nella pagina dei moduli le descrizioni associate al modulo provengono dal file miomodulo.info contenuto nella directory del modulo. All’interno del file sono contenute almeno le prime due variabili:
$Id$ name = miomodulo description = "Descrizione MioModulo" dependencies = modulo1 modulo2 modulo3 package = MieModuli
con i seguenti significati
Pagina dei blocchi
Nome del blocco nella lista blocchi
Funzione miomodulo_block($op=’list’)
Esempio:
<?php
function miomodulo_block($op = 'list', $delta = 0)
{
if ($op == "list")
{
$block[0]["info"] = t('MioBlocco');
return $block;
}
}
?>* Descrizione dell'help all’interno della configurazione del blocco
Funzione miomodulo_help($section = "")
Come definito al paragrafo Accesso ai moduli:permessi, i permessi di accesso ai moduli sono definiti mediante la funzione miomodulo_perm()
<?php
function miomodulo_perm()
{
return array("amministra contenuti miomodulo",
"crea contenuti miomodulo");
}
?>Il valore di $section deve essere verificato posizionando il cursore sul link ‘configura’ della pagina dei blocchi e vedere a quale percorso punta. Generalmente è admin/build/block/configure/MioBlocco/0 e quindi scrivere la funzione miomodulo_help() nel seguente modo:
<?php
function miomodulo_help($section = "")
{
$output = "";
switch ($section)
{
case "admin/build/block/configure/MioBlocco/0":
$output = "<p>" . t("Descrizione di MioBlocco") . "</p>";
break;
default:
}
return $output;
}
?> Pagina del controllo accessi utenti
Come definito al paragrafo Accesso ai moduli:permessi, i permessi di accesso ai moduli sono definiti mediante la funzione miomodulo_perm()
<?php
function miomodulo_perm()
{
return array("amministra contenuti miomodulo",
"crea contenuti miomodulo");
}
?>Quando un modulo ha fogli di stile propri, questi devono essere caricati prima di visualizzare il contenuto della pagina generata dal modulo. Nella pagina HTML generata da Drupal i file di stile compaiono secondo la sequenza:
stile/i del modulo corrente
stile/i del modulo corrente contenuti nel tema corrente
stili di default di Drupal
stili del tema corrente
come di seguito indicato.
<style type="text/css" media="all">@import "/sites/all/modules/miomodulo/miomodulo.css"</style>
<style type="text/css" media="all">@import "/sites/all/themes/miotema/miomodulo.css"</style>
<style type="text/css" media="all">@import "/modules/book/book.css"</style>
<style type="text/css" media="all">@import "/modules/node/node.css"</style>
<style type="text/css" media="all">@import "/modules/system/defaults.css"</style>
<style type="text/css" media="all">@import "/modules/system/system.css"</style>
<style type="text/css" media="all">@import "/modules/user/user.css"</style>
...
<style type="text/css" media="all">@import"/sites/all/themes/miotema/style.css"</style>
Per fare questo è utilizzata la funzione drupal_add_css() secondo il codice riportato.
L'esempio riporta il codice necessario per caricare il foglio di stile miomodulo.css.
Questo codice deve essere chiamato dalle funzioni del modulo che preparano codice HTML.
function miomodulo_css_file() {
$css_files = array(); // array in cui definire i file css
// Definisce i percorsi dei file di stile
$file_css_modulo = drupal_get_path('module', 'miomodulo') . '/miomodulo.css';
$file_css_modulo_in tema = path_to_theme() . '/miomodulo.css'; // se esistente
// Definisce nell'array lo stile di default del modulo
$css_files[] = array('file' => $file_css_modulo, 'type' => 'module', );
/*
Definisce nell'array lo stile ripetuto nella directory del tema corrente
Se esiste un file di stile nella directory del tema corrente
con lo stesso nome dello stile del modulo lo carica.
*/
if (file_exists($file_css_modulo_in tema) {
$css_files[] = array('file' => $file_css_modulo_in tema, 'type' => 'theme', );
}
// Avvisa Drupal di caricare i fogli definiti
foreach ($css_files as $css_file)
{
drupal_add_css($css_file['file'], $css_file['type'], 'all', false);
}
} La tabella BLOCKS contiene le informazioni sui blocchi:tipo, regole di accesso, tema , regione etc.
Tabella BLOCKS I campi sono i seguenti:
| module | T | indica da quale modulo è gestito il blocco |
| delta | T | identificativo univoco del blocco in riferimento al proprio modulo |
| theme | T | indica che il blocco può essere visualizzato per il tema |
| status | N | =1 il blocco è abilitato |
| weight | N | ordine di visualizzazione del blocco |
| region | T | indica la regione in cui deve essere visualizzato |
| custom | T | |
| throttle | T | |
| visibility | N | indica il tipo di visualizzazione delle pagine |
| pages | T | elenco delle pagine in cui è vera il tipo di visibility |
| title | T | titolo del blocco |
| bid | N | identificativo univoco del blocco |
| cache | N | assume valore 1 o -1 |
La tabella BLOCK_ROLES riporta l'identificativo rid (roles identifier) che indica il ruolo necessario per
visualizzare il blocco. I ruoli sono definiti nella tabella dei ruoli "role"
Tabella BLOCK_ROLES I campi sono i seguenti:
| module | T | indica da quale modulo è gestito il blocco |
| delta | T | identificativo univoco del blocco in riferimento al proprio modulo |
| rid | N | iidentificativo univoco del ruolo (vedi tabella role) |
La tabella BOXES contiene il contenuti dei blocchi gestiti dal modulo block.
Tabella BOXES I campi sono i seguenti:
| bid | N | iidentificativo univoco del blocco |
| body | T | il contenuto del blocco |
| info | T | ripete il titolo del blocco |
| format | N | tipo di formato (da tabella FILTER_FORMATS) |
La tabella MENU_CUSTOM contiene l'elenco di tutti i menu definiti dall'utente oltre ai menu di navigazione 'navigation', 'primary-links' e 'secondary-links'.
Tabella menu_custom I campi sono i seguenti:
| menu_name | T | identificativo interno del menu |
| title | T | titolo del menu visualizzato |
| description | T | descrizione del menu |
La tabella MENU_LINKS contiene informazioni relative alla struttura del albero del menu con tanti record quante sono le voci del menu. Per ogni voce è definita l' url a cui punta (link_path).
Tabella menu_links I campi sono i seguenti:
| menu_name | T | nome del menu |
| mlid | N | identificativo univoco della voce all'interno del |
| plid | N | identificativo univoco del padre |
| link_path | T | path a cui punta la voce del menu |
| router_path | T | path a cui punta la voce del menu definito in MENU |
| link_title | T | titolo della voce |
| options | T | valori degli attributi in forma serializzata |
| module | T | nome del modulo che gestisce il menu |
| hidden | N | =1 la voce del menu deve essere nascosta |
| external | N | =1 la voce del menu punta a una URL esterna al sit |
| has_children | N | =1 la voce ha figli |
| expanded | N | =1 la voce deve essere espansa |
| weight | N | ordine della voce all'interno del meni |
| depth | N | profondita della voce |
| customized | N | |
| p1 | N | identificativo del nodo radice dell'albero |
| p2 | N | identificativo del padre di secondo livello |
| p3 | N | identificativo del padre di terzo livello |
| p4 | N | identificativo del padre di quarto livello |
| p5 | N | identificativo del padre di quinto livello |
| p6 | N | identificativo del padre di sesto livello |
| p7 | N | identificativo del padre di settimo livello |
| p8 | N | identificativo del padre di ottavo livello |
| p9 | N | identificativo del padre di nono livello |
| updated | N | |
La tabella MENU_ROUTER contiene le informazioni sulle funzioni da attivare per raggiungere la pagina richiesta nel menu
Tabella menu_router I campi sono i seguenti:
| path | T | percorso paramentrizzato a cui puntare (Es: node/%/edit) |
| load_functions | T | funzione di caricamento (load) |
| to_arg_functions | T | argomenti della funzione di caricamento |
| access_callback | T | funzione che controlla l'accesso al menu |
| access_arguments | T | argomenti della funzione di accesso |
| page_callback | T | funzione di visualizzazione della pagina richiesta |
| page_arguments | T | argomenti della funzione di visualizzazione |
| fit | N | ordine in cui vengono selezionati i possibili path [vedi menu_get_item()] |
| number_parts | N | uso interno |
| tab_parent | T | ?? |
| tab_root | T | ?? |
| title | T | titolo della voce di menu |
| title_callback | T | funzione di conversione del titolo [t(); check_plain() etc.] |
| title_arguments | T | ?? |
| type | N | ?? |
| block_callback | T | ?? |
| description | T | descrizione della voce |
| position | T | ?? |
| weight | N | ordine di visualizzazione |
| file | T | eventuale file di template da caricare prima di chiamare la page_callback |
La tabella NODE contiene l'elenco di tutti i nodi inseriti nel sistema. Per un sito multilingua ogni traduzione introduce un nuovo nodo che si riferisce alla lingua di traduzione.
Tabella node I campi sono i seguenti:
| nid | N | identificativo univoco del nodo |
| vid | N | identificativo nel numero di revisione nella tabella NODE_REVISONS |
| type | T | tipo del nodo. Tabella di codifica NODE_TYPE |
| title | T | titolo del nodo |
| uid | N | identificativo utente del proprietario del nodo |
| status | N | =0 non visibile; =1 visibile |
| created | N | timestamp della data di creazione del nodo |
| changed | N | timestamp della data di modifica del nodo |
| comment | N | identificativo utente dell'ultimo commento |
| promote | N | =1 il nodo è visualizzato in prima pagina |
| moderate | N | =1 il nodo deve essere controllato prima della pubblicazione |
| sticky | N | numero d'ordine del nodo nella prima pagina |
| language | T | lingua del contenuto:'it' , 'en', 'fr', … |
| tnid | N | identificativo univoco del nodo sorgente per le traduzioni |
| translate | N | =1 deve essere aggiornata la traduzione. Il nodo sorgente è cambiato |
La tabella NODE_REVISIONS contiene le informazioni sul contenuto principale dei nodi (body) , sul sommario (teaser) , il titolo (title) e le revisioni eseguite. Inoltre il campo format indica come il contenuto deve essere filtrato, prima di visualizzarlo. Ogni nodo ha quindi più record indicatii dall'identificativo univoco del nodo stesso (nid) e dall'identificativo della revisione (vid).
Tabella node_revisions I campi sono i seguenti:
| nid | N | identificativo univoco del nodo |
| vid | N | identificativo del numero di revisione |
| uid | N | identificativo utente del proprietario del nodo |
| title | T | titolo del nodo per la revisione corrente |
| body | T | contenuto del nodo per la revisione corrente |
| teaser | T | sommario del nodo per la revisione corrente |
| log | T | Messaggio di log contenente le modifiche eseguite |
| timestamp | N | data di modifica del nodo |
| format | N | formato del nodo da tabella FILTERS_FORMAT |
La tabella ROLE indica i ruoli che possono essere assegnati ad un utente. Ad esempio, amministratore, webmaster, etc
Mediante i ruoli possono essere nascosti contenuti, blocchi e menu.
Tabella ROLE I campi sono i seguenti:
| rid | N | iidentificativo univoco del ruolo |
| name | T | nome del ruolo |
La tabella URL_ALIAS definisce la tabella di corrispondenza tra un percorso interno al sistema e un alias del percorso definito dall'utente
Tabella url_alias I campi sono i seguenti:
| pid | N | identificativo univoco del path |
| src | T | percorso originale |
| dst | T | alias del percorso |
| language | T | linguaggio associato all'alias del percorso |
La tabella USERS contiene informazioni sugli utenti
Tabella users I campi sono i seguenti:
| uid | N | identificativo utente |
| name | T | nome utente |
| pass | T | password utente |
| T | mail utente | |
| mode | N | modo di visualizzazione del commento:threaded o flat |
| sort | N | modo per l'ordinamento dei commenti |
| threshold | N | non più usato |
| theme | T | tema di default |
| signature | T | firma utente |
| created | N | timestamp della data di creazione del nodo |
| access | N | timestamp ultimo accesso |
| login | N | timestamp ultimo login utente |
| status | N | =0 utente bloccato, =1 utente attivo |
| timezone | T | timezone dell'utente |
| language | T | lingua di default |
| picture | T | percorso all'immagine utente |
| init | T | email forniti al momento della registrazione |
| data | T | serializzazione di un array che rappresenta i campi dela form utente |
| timezone_name | T | nome timezone tipo Europe/Rome |
La tabella USERS_ROLES indica i ruoli assegnati a ciascun utente. Nella visualizzazione dei blocchi , questo permette di nascondere i blocchi agli utenti senza il ruolo richiesto per la visualizzazione
Tabella USERS_ROLES I campi sono i seguenti:
| uid | N | identificativo univoco dell'utente |
| rid | N | iidentificativo univoco del ruolo |
Sono riportati in questo capitolo alcuni concetti che saranno utilizzati nel proseguo di questa documentazione.
In questa documentazione sarà indicato con il termine di contenuto l'informazione archiviata in un sistema CMS come Drupal.
L'informazione pubblicata è orientata alla diffusione di conoscenza , idee, proposte e altro che gli ideatori del sito hanno come loro missione. L'informazione è resa disponibile nel sito web sotto forma di articoli, libri, forum e ancora con il supporto di immagini , video e suoni.
Tutto questo è quello che chiameremo contenuto primario del sito.
Ma oltre al contenuto primario, nel sito sono presenti altri contenuti come i menu per la navigazione, maschere per l'interazione con l'utente, commenti agli argomenti lasciati dai visitatori o utenti del sito, pubblicità e tutto ciò che può essere necessario per raggiungere lo scopo finale per cui il sito è stato pensato.
Tutto questo è quello che chiameremo contenuto secondario del sito
Il contenuto primario viene gestito dal Drupal attraverso i NODI.
Possiamo pensare al nodo come il contenitore della nostra informazione che viene poi visualizzato sul web sotto forma di pagina singola o di pagina di un libro o ancora come contenuto di un singolo intervento in un forum.
Drupal mette a disposizione dei nodi di base come appunto la creazione di una singola pagina o di un pagina appartenente ad un libro come questa che state leggendo. Ma Drupal consente anche di creare nuove tipologie di nodi. Si potrebbe creare quindi una rubrica telefonica dove ogni nodo è costituito da un singolo nominativo , uno scadenzario, un reportage fotografico e così via.
Il contenuto secondario viene gestito da Drupal attraverso i BLOCCHI.
I menu di navigazione sono dei blocchi, l'elenco degli ultimi commenti alle pagine o delle ultime discussioni aperte in un forum sono dei blocchi, la maschera di login è un blocco così come i tag di ricerca delle pagine. In pratica, come detto, tutto ciò che è utile per una buona navigazione e fruibilità del sito va a finire in un blocco.
Quando viene inviata una richiesta, Drupal mediante la tabella MENU_ROUTER individua la funzione da chiamare per leggere, codificare e visualizzare il contenuto richiesto. Questa specifica funzione viene indicata con il nome di page callback.
Ad esempio la richiesta di un singolo nodo seleziona la page callback node_page_view() , per la visualizzazione della prima pagina node_page_default().
Drupal archivia il contenuto primario nei nodi. All'interno del database i nodi sono numerati sequenzialmente.
Per accedere ad un nodo e quindi al suo contenuto , è necessario indicare a Drupal l'identificativo del nodo che si vuole estrarre dal database. Questa informazione è contenuta nell' URL inserito nel browser.
Ad esempio:
URL = www.miosito.com/node/345
Con questo URL diciamo al sistema di mostrarci il contenuto del nodo 345.
Questo URL è un po' criptico perchè non dice nulla circa il contenuto del nodo a meno di non ricordarsi che il nodo 345 corrisponde ad un certo contenuto che è molto improbabile.
Drupal viene in aiuto con gli URL alias.
In pratica è possibile associare all' URL precedente un qualsiasi altro URL .
Ad esempio:
URL = www.miosito.com/contabilita/elenco-fatture/attive
Si noti che tre voci 'contabilita' 'elenco-fatture' 'attive' sostituiscono due voci 'node' '345'.
In questo modo non interessa più sapere quale nodo chiamare per avere l'elenco delle fatture attive, in quanto abbiamo un alias più facilmente ricostruibile.
Sarà compito di Drupal convertire l' URL alias in un URL di sistema e richiamare successivamente la funzioni per visualizzare il contenuto.