Nei precedenti articoli si è visto come modellare I contenuti, in astratto, secondo un preciso content model. Una volta che il modello dei contenuti sia stato definito, è ora possibile passare al rendering del content model e vedere un po’ di codice.
Introduzione
Nelle precedenti puntate abbiamo visto in astratto come modellare i contenuti. Assumendo che un modello di contenuti adesso sia stato ragionevolmente definito, in questo articolo vedremo finalmente un po’ di codice, quello che un programmatore Java si aspetterebbe fin dal principio e che invece in questo caso è stato semplicemente rimandato fino a qui.
Non mi stancherò mai di ripetere, anche se purtroppo è un errore commesso molto frequentemente, che WCS non è un generico ambiente di esecuzione di JSP, ma ha delle regole precise che vanno rispettate. In particolare i template sono generalmente cachizzati: chiamando un template non è detto che venga eseguito del codice; invece è probabile che venga estratto dalla cache codice HTML preventivamente calcolato. Quindi non è possibile scrivere del codice assumendo che ogni template venga eseguito ogni volta che la pagina viene invocata.
Il modello dei contenuti non è in generale semplicissimo. Ci sono vari casi da esaminare in base a come è strutturato il modello. Come abbiamo visto, possiamo avere parent, content, basic e flex asset e altre problematiche come la definizione di associazioni (per i basic asset) o di attribute che puntano ad un altro asset (per il flex).
Iniziamo quindi a vedere alcuni dei casi principali.
L’ambiente “ics”
Innanzitutto i template hanno un ambiente (chiamato ics per Interface to Content Server) che contiene degli “oggetti” (nel senso Java vero e proprio). Gli oggetti contenuti nell’ambiente sono di vario tipo, ma due tipi sono importanti per lo sviluppatore WCS: liste e variabili.
Nel listato seguente sono riassunti i tag utilizzabili per leggere questi oggetti:
Extract Data (tag)
Var List List & Var
Le variabili vengono valorizzate nei parametri della URL, nelle chiamate dei template oppure direttamente nella definizione del template. Quindi se si chiama un template specificando cid=123456 la variabile cid sarà stata valorizzata e potrà essere visualizzata. Il tag ics:getvar non fa altro che leggere la variabile e scriverla nell’output.
Sono molto importanti anche le liste, che in realtà non vanno pensate come liste di valori, ma come liste di record (o se volete, come liste di mappe). Il caso di lista semplice con un valore solo è implementato con una lista che contiene una mappa iul cui valore è accessibile con la chiave value.
Le liste sono iterabili utilizzando il tag listloop. L’uso tipico di una lista è il ciclo per estrarne e visualizzarne i valori.
Questo ciclo per ogni elemento della lista genera in output il valore associato con la mappa corrispondente. O, in parole più semplici, se si pensa che una lista di record è una tabella, visualizza una colonna della tabella.
Vedremo più avanti che le tabelle sono spesso ottenute quando si estraggono valori di attributi (che possono essere multipli, e per questo sono delle liste e non delle semplici variabili).
Utilizzare i tag ics:get e ics:listget non è il solo modo di estrarre i valori da variabili e liste. Le JSP prevedono anche un’altra sintassi riassunta di seguito:
Extract/Check Values
GetVar <%=ics.GetVar("var") %> <%=ics.GetVar("var") != null %> GetList <%=ics.GetList("List").getValue("value") %> <%=ics.GetList("List") !=null && ics.GetList("List").hasData() %>
Questa sintassi è decisamente più brutta, ma purtroppo è l’unica utilizzabile quando il valore che vogliamo utilizzare deve essere usato come attributo di un tag. Questo è molto importante quando si invocano altri template utilizzando la fondamentale chiamata calltemplate, che andiamo a vedere.
La calltemplate
Di seguito è sintetizzata la calltemplate, che è assolutamente vitale quando si effettua il rendering di un modello di contenuti:
render:calltemplate
<render:calltemplate tid="<%=ics.GetVar("tid") %>" site="<%=ics.GetVar("site") %>" c="<%=ics.GetVar("c") %>" cid="<%=ics.GetVar("cid") %>" slotname="Detail" tnmame="Detail"> <render:argument name="p" value= "<%=ics.GetVar("p")%>"/>
Prima di entrare nei dettagli dei parametri del tag, ricordo come si effettua il rendering di un modello di contenuti secondo le line guida standard di WCS:
- viene selezionato un asset, identificandolo per id e per tipo;
- vengono estratti i valori specifici dell’asset (è spiegato nei prossimi paragrafi);
- il risultato sono delle liste e delle variabili, come spiegato prima; questi valori vengono visualizzati;
- se si incontrano altri asset durante il rendering (per esempio figli, o attributi che sono riferimenti ad altri asset), si deve selezionare l’altro asset e invocare una diversa calltemplate per renderizzare lo specifico asset.
Questo in pratica si traduce nel chiamare una diversa calltemplate ogni volta che si incontra un altro asset.
La calltemplate è piuttosto verbosa in quanto richiede una considerevole quantità di paramentri. Per fortuna, site e tid normalmente non cambiano (sono impostati implicitamente dal sistema), e quindi vengono passati così come sono. Invece c e cid rappresentano l’asset corrente. Tradizionalment il parameter c contiene il tipo dell’asset mentre il cid contiene l’id, come si intuisce. Applicando le regole descritte prima, c e cid dovrebbero sempre avere un valore facile da identificare: o sono i valori passati nell’URL, o sono i valori estratti da attributo o da una associazione.
Rimane sostanzialmente da specificare caso per caso tname, che segue una semplice regola: se il nome inizia con ‘/‘ il template invocato si considera “senza tipo”, mentre se non comincia con ‘/’ si considera “tipizzato”. Questo in pratica significa the se il tname è qualcosa come ‘/Layout‘, allora verrà invocato il template che si chiama proprio /Layout. Altrimenti se il tname è “relativo”, il realtà verrà invocato un template il cui nome è uguale a
"ics.GetVar("c")+"/"+ics.GetVar("tname")
Tradotto in pratica, se invoco il template tname=’Body’ e il c corrente è Page, il template effettivamente invocato sarà Page/Body, mentre se il c è Article verrà invocato Article/Body.
Questo meccanismo è utilissimo per implementare il sistema di templating modulare e tipizzato che è stato descritto nelle precedenti puntate.
Rendering di un basic asset
Completiamo il quadro adesso illustrando come si estraggono i dati da un asset. Sono possibili sostanzialmente due casi: Basic Asset e Flex Asset. Di seguito sono sintetizzati i tag che servono per estrarre i dati da un basic asset.
Get Basic Asset Data
<asset:load name="currentPage" type="Page" objectid="<%=ics.GetVar("cid") %>"/> <asset:get name="currentPage" field="description" output="description"/>
La modalità è abbastanza simile a quella dell’estrazione dei dati con un JavaBean in una applicazione Java che fa uso di ORM: viene caricato il record in un bean e poi vengono letti i singoli campi del record come proprietà del bean. La chiamata asset:load legge l’asset, nell’esempio di tipo Page e di id cid (in questo caso passato nella variabile cid). A questo punto nell’ambiente c’è un oggetto chiamato currentPage.
Come dicevo prima, nell’ambiente non si hanno solo liste e variabili ma anche generic POJO Java. I POJO generati sono però generalmente opachi allo sviluppatore, eccetto per la lettura di campi che viene fatta con la asset:get. Finalmente, dopo questa chiamata, il valore del campo dell’asset è posto in una variabile (specificata da output in asset:get) e può essere visualizzato.
Rendering degli attributi di un flex asset
Nell’esempio precedente abbiamo visto come fare ad estrarre i dati da un Basic Asset, ma nella maggior parte dei casi WCS utilizza i Flex Asset. I Flex Asset hanno una struttura un po’ più complessa: sono infatti memorizzati come un asset principale, il “padre”, e una serie di attributi correlati, i “figli”. Qui di seguito possiamo vedere come estrarre il valore di un attributo:
Get Flex Asset Data
<assetset:setasset type=‘<%=ics.GetVar("c") %>' id=‘<%=ics.GetVar("cid") %>' name="myAssetSet"/> <assetset:getattributevalues name="myAssetSet" attribute="Attr" listvarname="Attr" typename="Content_A" />
Nel primo passo, si utilizza la chiamata assetset:setasset. Questa chiamata crea un POJO speciale di tipo myAssetSet che è in pratica il padre degli attributi. A questo punto è possibile utilizzarlo con il tag assetset:getattributevalues che ha la capacità di produrre una lista (la lista Attr) di tutti i valori dell’attributo che appartengono all’asset selezionato. Ricordiamo che in generale un attributo può avere valori multipli quindi il tag ritorna sempre una lista , e ogni record della lista ha un solo campo, che si chiama value.
Un importante trucco: siccome le liste sono sempre posizionate al primo record, è possibile utilizzare il tag listget senza doverlo inserire in un listloop. Quindi se sappiamo che vogliamo estrarre un attributo con un valore singolo, possiamo scrivere direttamente
per ottenere il valore senza cicli. Questo rende i flex attribute quasi tanto semplici da usare anche se è riconosciuto che i flex sono in generale più complicati da usare.
Conclusioni
Abbiamo visto come fare a renderizzare il modello almeno nei casi principali. In realtà la libreria di tag offerta da WCS è ben più ampia di così e offre una grande quantità di servizi, inclusi blog, ricerche, invio di email, workflow e molto altro, che non possono essere coperti in questo breve spazio. Invitiamo a consultare la documentazione allegata in WCS per i dettagli.