[risolto] Cck: come creare questo tipo di contenuto?

34 contenuti / 0 new
Ultimo contenuto
[risolto] Cck: come creare questo tipo di contenuto?

Ciao a tutti.
Sono tre giorni che sto impazzendo e non riesco a trovare una soluzione a questo mio problema.
Quello che sto cercando di fare è molto simile ad un menu per ristoranti. Quindi:

|categoria|
|campo1|campo2|

Io vorrei che il cliente potesse aggiungere la seconda riga (quella con campo1 e campo2), un numero illimitato di volte. Tornando all'esempio del menu per ristoranti, un campo categoria ("primi piatti") e aggiungere più righe "piatto" - "prezzo".
|categoria|
|campo1|campo2|
|campo1|campo2|
|campo1|campo2|
ecc.

Fin qui ci siamo, ho trovato qualche soluzione.
Il problema sta nel momento in cui si vuole aggiungere una nuova "categoria". Come faccio ad aggiungerla sotto le righe campo1|campo2 appena create? Se rendo anche il campo "categoria" illimitato, quando l'utente clicca su "Add more" succede questo:
|categoria|
|categoria|
|campo1|campo2|
|campo1|campo2|
|campo1|campo2|

mentre io vorrei:
|categoria|
|campo1|campo2|
|campo1|campo2|
|campo1|campo2|
|categoria|
e poi continuare ancora con
|campo1|campo2|

Una possibilità potrebbe essere quella di avere più gruppi di field organizzati in questa maniera, ma dovrei crearli a priori. Ma non conosco il numero esatto (dipende dal cliente).
Ho provato anche ad utilizzare CCK3, che ha l'opzione Multigroup. Ma niente da fare.
Non penso che tutto ciò si possa fare con cck, quindi devo inventarmi qualcosa di "creativo" per giungere ad una soluzione. Mi basterebbe anche una textarea a due colonne, da quanto disperato sono!
ps. campo1 e campo2 sono 2 textfield distinte, ma potrei anche creare un solo campo cck che contenga due textfield seguendo questo bellissimo tutorial.

Field Collection è per D7, mi sono dimenticato di specificare che uso D6.
Flexifield lo avevo considerato ma mi dava dei problemi se lo rendevo unlimited.
Per quanto riguarda CCK Fullname il problema è sempre quello. Anche se utilizzo tre campi (ad esempio Prefix, First e Last), quando aggiungo un altro "fullname", mi ritrovo 3 campi. Io vorrei aggiungerne 2 alla volta, tenendo il primo fisso (la categoria). Poi, nel momento in cui il cliente vuole aggiungere una nuova categoria, dargli la possibilità di ritrovarsi nuovamente i 3 campi completi.
Non so se mi sono spiegato bene, inoltre non capisco se questo sia l'approccio giusto.

Ciao benipulp,
ti dico la verità... non ho capito benissimo quello che intendi...
Se non sbaglio il tuo intento è quello di avere la possibilità di creare n categorie. Ogni categoria deve avere la possibilità di aggiungere al suo interno n coppie di campi |campo1|campo2|.

Secondo me potresti leggere questi articoli che parlano della creazione di un modulo Compound Field.

http://www.poplarware.com/articles/cck_field_module
http://www.lullabot.com/articles/creating-custom-cck-fields
http://www.darcynorman.net/2008/05/02/creating-a-custom-compound-field-f...

Sicuramente non è la soluzione più semplice ed indolore… pero' potrebbe aiutarti…
prova a dare un'occhiata.
Ciao!!

I Dubbi te li crea la libertà.
http://www.texas138.com

Ciao texas138, i 3 link che hai postato facevano già parte dei miei preferiti...
Infatti creare una field ad hoc è quello che sto pensando di fare. Il problema però è questo, vediamo se riesco a spiegarmi meglio. CCK offre la possibilità (settando gli allowed values su unlimited) di poter aggiungere un nuovo campo con il bottone "add more item". Perfetto. Se io creo ad hoc un cck field con 3 campi (uno per la categoria e due per nome e prezzo), tipo così:

|descrizione|
|nome||prezzo|

quando clicco su "add more" mi duplica ovviamente tutti e tre i campi. Se un utente però sta creando il suo menu, e vuole aggiungere n campi nome-prezzo di una stessa categoria? Ad esempio, n piatti della categoria "antipasti"?
Vorrei che risultasse una cosa del genere:
|antipasti|
|tartina||2€|
|prosciutto e melone||5€|
ecc.

Però CCK mi permette solo di duplicare l'intero "gruppo" ed il risultato è:
|antipasti|
|tartina||2€|
|antipasti|
|prosciutto e melone||5€|
ecc.

E come soluzione non è delle migliori per vari motivi, tra cui:
1. lentezza dell'operazione: un utente dovrebbe riscrivere la parola "antipasti" (o "primi", "secondi", ecc) ogni volta che inserisce un piatto.
2. sarebbe brutto dal punto di vista grafico

Per questo ho deciso di chiedere il vostro aiuto perché comincio a pensare che questo non sia l'approccio giusto.
Avevo pensato ad una soluzione più spartana anche. Ammesso e non concesso che io riesca ad allineare (in fase di editing del content type) due textarea potrei fare una cosa del genere:

http://www.drupalitalia.org/sites/drupalitalia.org/files/esempio_1.jpg

Così l'utente potrebbe scrivere a sx il nome del piatto e a dx il prezzo. Dovrebbe però essere sufficientemente "intelligente" da mettere i giusti invii...

Non so davvero che fare!

Crei un tipo di contenuto prodotto, come campi metti piatto e prezzo, poi con la tassonomia gestisci l'antipasti, con views poi puoi ragguppare per tassonomia.

no no ti prego... due textarea no!!! non è stile drupal!!! ahahahah
no a parte gli scherzi, quello che ha scritto sopra ealmumo è un'altra soluzione possibile...

però scusa... e premetto... se dico una caaaaavolata fermatemi perchè Agosto mi fa delirare... ho un'idea...
Crei 2 compound field... il primo ha un campo "categoria" di tipo testuale ed un campo di tipo "info-piatto" che è il secondo compound field!!!!
il secondo compound field (info-piatto) avrà come campi "nome" e "prezzo"...

Io farei un po di tentativi... pero' non sono sicuro di quello che dico...

I Dubbi te li crea la libertà.
http://www.texas138.com

@ ealmumo

Se ho capito bene, intendi: creo un tipo di contenuto prodotto con i due campi e poi nello stesso contenuto associo il termine della tassonomia (antipasto, primo, ecc).
Il problema è che con questo metodo avrei un sacco di nodi in più. Mettiamo che il mio sito abbia 10000 utenti. Se ognuno di essi creasse un menu completo, dovrebbe creare un nodo per gli antipasti, uno per i primi, uno per i secondi, ecc. Quindi avrei 40000 nodi invece di 10000, ben 30000 in più. Senza contare che il procedimento non sarebbe semplice e chiaro, che è quello che cerco.
Ho pensato anche ad un'unica textarea con un editor wysiwyg per permettere un minimo di formattazione. Ma anche qui ci sarebbero un sacco di complicazioni. La formattazione del testo non è sempre la stessa (dipende da come ogni singolo utente formatta il testo), in più non sarebbe neppure allineata come una tabella (se volessi i prezzi tutti allineati a dx come faccio?).

Allora vai con i computed field (nei link sopra ci sono anche i pacchetti pronti), io pensavo fosse per il sito di un ristorante.

Sì ma anche creando un compound field ad hoc, resta sempre il problema che non riesco a risolvere: nel momento in cui io clicco su "Add another item", l'intero gruppo dei campi mi viene duplicato. Non resta fermo per capirci il campo "antipasto" e si duplica la seconda riga (con "info" e "prezzo"). O meglio, con CCK3 si può fare una cosa simile con multigroup. Cioè, creo un gruppo standard con all'interno un campo textfield e un multigroup. All'interno di questo multigroup inserisco due campi textfield con valore unlimited. Quando clicco su "add more values" solo il multigroup viene duplicato. Però non so se fidarmi di CCK3 che è ancora in versione alpha per D6.
In ogni caso resta sempre l'altro problema: quando l'utente ha finito con gli antipasti, come fa a partire con una nuova categoria?
L'unica cosa che mi viene in mente è: definisco io a priori le categorie (ad esempio antipasti, primi, secondi, bibite, dessert) e creo già questi campi. Ogni ristorante avrà quindi al max 5 categorie in cui inserire i propri piatti e amen!

La gestione potrebbe essere sempre con la tassonomia o crearne 2.

Quote:
La gestione potrebbe essere sempre con la tassonomia o crearne 2.

Scusa non capisco!

O gestisci

Quote:
L'unica cosa che mi viene in mente è: definisco io a priori le categorie (ad esempio antipasti, primi, secondi, bibite, dessert) e creo già questi campi. Ogni ristorante avrà quindi al max 5 categorie in cui inserire i propri piatti e amen!

Oppure puoi crearti un modulo personalizzato, che crei i campi.

Niente da fare. Più ci penso e meno l'ipotesi dei campi CCK mi piace. Ho paura di trovarmi con nodi da oltre 100 campi (bastano solo 50 piatti per arrivarci) ed ho il timore che questi, oltre ad essere poco gestibili (metti che un utente vuole aggiornare il suo menu), mi rallentino il sito..
Non esistono altri modi?
Che ne so, sparo a caso, un editor con un template predefinito, importare un qualcosa, usare google docs!

I template si fanno con cck, per il tuo caso hai la soluzione della tassonomia o di un tuo modulo, altre non ne vedo.

Ma secondo te, a livello di prestazioni, un nodo con 100 cck ne risente? O posso stare tranquillo?
Inoltre, come posso cancellare dal db i campi precedentemente inseriti? Ho notato che quando clicco sull'immagine a dx di ogni "item" (in edit) questo si cancella ma non dal db, soltanto dalla visualizzazione. L'ho notato perché usando views li vedo ancora.

C'è un'alternativa che nessuno ti ha proposto, ancora.
Scrivi un modulo che implementa quello che ti serve, esattamente come ti serve.

La realtà è che i moduli che implementano soluzioni generiche coprono forse il 95% dei casi, ma ci sarà sempre qualcosa che è più facile da fare 'sporcandosi le mani' con il php.

Angelo Turetta

@aturetta proposta 2 volte nei post sopra.

Comunque a rigor di logica secondo te pesa di più un nodo con 100 campi o 100 nodi con 1 campo, il primo meno perché non ha commenti associati, alias e simili.
Lo salvi il nodo poi? Altrimenti devi modificare il modulo per farlo cancellare, oppure li salva come revisione?

Il modulo lo farei volentieri, peccato che non ne sia capace!
@ealmuno
Sì è ovvio che sia meglio un nodo con 100 campi piuttosto che 100 nodi. Ma un nodo con un'unica textarea (o qualcosa di meglio, solo che non mi viene in mente nulla) che contenga tutte le informazioni invece di 100 campi penso sia più snello. Il problema è appunto: esistono alternative? Oltre al modulo che non so crearmi da solo?
Il nodo lo salvo senza revisione. Siccome vorrei che un utente potesse crearsi il proprio menu, ho intenzione di usare content profile per questo, in modo di permettergli di creare e modificare un solo menu.
Noto solo ora, perché mi hai fatto venire il dubbio, che su CCK2 non appare nessun link accanto ad ogni "item" per cancellarlo; è una caratteristica di CCK3! Quindi se usassi CCK2 (e fino ad oggi era nei miei intenti), o un utente cancella del tutto il menu o niente! Finché si tratta di aggiungere o ordinare ancora ancora, ma non può cancellare le righe una per una...
Come fare? CCK3 lo potrei usare? Specifico che il fine di tutto questo casino è un sito molto grosso e ad alto traffico: vale la pena di affidarsi ad un modulo così importante (insieme a views copre il 95% delle funzioni del mio progetto) in versione alpha?

Se non sai fare il modulo non hai altre soluzioni, si può scegliere solo quando si hanno scelte.

Va bene, dopo circa una settimana di meditazioni e consigli, ho deciso di creare un compund field con tre campi: nome, descrizione e prezzo. Questo compound avrà valore "unlimited" su "allowed values". Il content type sarà quindi così composto (con CCK2):

campo textfield - categoria 1 (un solo valore, non "unlimited")
campo compound - piatti categoria 1 (unlimited)

campo textfield - categoria 2 (un solo valore, non "unlimited")
campo compound - piatti categoria 2 (unlimited)

ecc.

Ogni content type avrà tot gruppi "categorie" (numero ancora da decidere, minore di 10) e potrà dunque aggiungere solo tot categorie (antipasti, primo, sushi, panini, ecc). Se vi fosse il bisogno di averne in più: mi dispiace!

Poi farò in modo che l'output di tutto questo stia in una tabella (quando ci riuscirò, posterò qui la soluzione).

Sto cercando di validare uno dei campi (quello del prezzo) nel modulo che sto creando per il compound field (ho seguito questo tutorial http://www.poplarware.com/articles/cck_field_module).
Il campo lo salvo nel db in questo modo:

$columns['prezzo_piatto'] = array('type' => 'numeric', 'precision' => 10, 'scale' => 2, 'not null' => FALSE, 'sortable' => TRUE, 'default' => '');

E il codice che sto usando per validare è questo:
/**
* Implementation of CCK hook_field().
*/
function restaurant_fld_field($op, &$node, $field, &$items, $teaser, $page) {
  switch ($op) {
    case 'validate':
      if (is_array($items)) {
        foreach ($items as $delta => $item) {
          if (!preg_match('/^[0-9]$/', $item['prezzo_piatto'])) {
            form_set_error($field['field_name'],t('"%prezzo_piatto" is not a valid number',array('%prezzo_piatto' => $item['prezzo_piatto'])));
          }
        }
     }
     break;

- Se digito un carattere normale ("abc") esce l'errore: "abc" is not a valid number
- Se digito un solo numero ("4") esce l'errore con questa scritta: "" is not a valid number
- Se invece digito più di un numero ("52") esce l'errore con questa scritta: "52" is not a valid number

Dove sbaglio? Inoltre, è giusto memorizzare come decimal la casella del prezzo (non devo farci calcoli successivamente)?

Sicuro del pregmartch?
http://php.net/manual/en/function.preg-match.php
/^[0-9]+$/

Niente da fare...
Ho provato anche con:
if (!preg_match('/^[\-+]?[0-9]*\.*\,?[0-9]+$/', $item['prezzo_piatto']))
e nulla.

Non è che sia sbagliato usare !preg_match?

Non credo, caso mai prova con
if (preg_match('/^[0-9]$/', $item['prezzo_piatto'])) {} else {
form_set_error($field['field_name'],t('"%prezzo_piatto" is not a valid number',array('%prezzo_piatto' => $item['prezzo_piatto'])));
}

Non credo, caso mai prova con

if (preg_match('/^[0-9]$/', $item['prezzo_piatto'])) {} else {
            form_set_error($field['field_name'],t('"%prezzo_piatto" is not a valid number',array('%prezzo_piatto' => $item['prezzo_piatto'])));
          }

Che scemo! L'errore era nei campi vuoti (quando il campo è unlimited aggiunge sempre un campo sotto), quindi ho messo un controllo. Inoltre visto che c'ero, ho pensato di aggiungere qualche riga (ben poco eleganti! se avete qualche miglioria fatevi avanti) per:
1. rendere i campi nome e prezzo obbligatori (se inseriti uno di loro)
2. controllare che se il campo descrizione viene inserito, sia presente il nome (e di conseguenza il prezzo)

case 'validate':
      if (is_array($items)) {
        foreach ($items as $delta => $item) {
if (!empty($item['nome_piatto']) && empty($item['prezzo_piatto'])) {
form_set_error($field['field_name'],t('Controllare i campi inseriti: il nome del piatto e il prezzo sono obbligatori.'));
}
elseif (!empty($item['prezzo_piatto']) && empty($item['nome_piatto'])) {
form_set_error($field['field_name'],t('Controllare i campi inseriti: il nome del piatto e il prezzo sono obbligatori.'));
}
elseif (!empty($item['descrizione_piatto']) && empty($item['nome_piatto'])) {
form_set_error($field['field_name'],t('Controllare i campi inseriti: il nome del piatto e il prezzo sono obbligatori.'));
}
elseif (strlen($item['prezzo_piatto']) > 0 && (!preg_match('/^[\-+]?[0-9]*\.?[0-9]+$/', $item['prezzo_piatto']))) {
            form_set_error($field['field_name'],t('"%prezzo_piatto" non è un numero valido. Inserire solo cifre e usare il punto al posto della virgola.',array('%prezzo_piatto' => $item['prezzo_piatto'])));
          }
        }
     }
     break;

Bene, ho quasi concluso ormai.
Ho creato il campo compound seguendo il tutorial citato sopra. Per fare in modo poi di stampare il tutto in una tabella ho aggiunto, sempre nel modulo del compound, questa funzione:

/**
* Theme function for default formatter.
*/
function theme_restaurant_fld_formatter_default($element = NULL) {
  if(empty($element['#item'])) {
    return '';
  }
  $stuff = $element['#item'];
if(empty($stuff['descrizione_piatto'])) {
$ret = '<tr><td class="cel-nome-piatto">' . $stuff['nome_piatto'] . '</td><td class="cel-prezzo-piatto">€'  . $stuff['prezzo_piatto'] . '</td></tr>';
}
else {
$ret = '<tr><td class="cel-nome-piatto">' . $stuff['nome_piatto'] . '</td><td class="cel-prezzo-piatto">€'  . $stuff['prezzo_piatto'] . '</td></tr><tr><td class="cel-descrizione-piatto">' . $stuff['descrizione_piatto'] . '</td></tr>';
}
  return $ret;
}

Poi ho creato un template per il mio tipo di contenuto: node-menupage.tpl.php. All'interno vi ho inserito (cancellando print content):

<table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria1[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria1 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
<?php if ($node->field_categoria2): ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria2[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria2 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php endif;?>

Come vedete, ho aggiunto un if per controllare se categoria2 esiste. Questo perché nella creazione del menu, l'utente dovrà inserire almeno una categoria (categoria1) fino ad un max di tot categorie (devo ancora decidere quante). Quindi ripeterò quel if tante volte quanto sarà necessario.
Le uniche due questioni che mi rimangono da sistemare sono:
1 - Con il codice qui sopra, i piatti della categoria2 sono stampati solo se field_categoria2 esiste. Ma un utente potrebbe accidentalmente non riempire quel campo scrivendo comunque i piatti. Come avvisarlo (cioè come validare) di riempire quella casella?
2 - Come posso fare in modo di distribuire in più pagine (o in altri modi, js?) un menu troppo lungo?

C'era un errore nel codice qui sopra. Bisogna sostituire:

<?php if ($node->field_categoria2): ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria2[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria2 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php endif;?>

con
<?php if (strlen($node->field_categoria2[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria2[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria2 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>

Resta comunque il problema della validazione. Qualche suggerimento? Aggiungo un semplice avviso testuale nella descrizione della field o mi avventuro nei meandri di php?

Io in passato ho usato flexifield e ho avuto problemi perché quella versione non supportava views, quindi estrarre i dati era uno strazio (i dati erano memorizzati come array serializzati).

Quando devo fare una cosa del genere in D6, adesso creo un modulo apposito creando un "compound field" (cercando questa stringa con Google, trovi un validissimo tutorial su come fare).

Quote:
Quando devo fare una cosa del genere in D6, adesso creo un modulo apposito creando un "compound field" (cercando questa stringa con Google, trovi un validissimo tutorial su come fare).

Ma è quello che ho fatto infatti! :)
Ho seguito questo tutorial (http://www.poplarware.com/articles/cck_field_module) e sono quasi certo che sia lo stesso a cui ti riferisci.
Ora mi resta da sistemare solo un paio di cose e poi potrò considerare chiusa e risolata l'intera faccenda:

  1. Per i menu troppo lunghi come posso fare per distribuire il testo in più pagine? E' giusto inoltre farlo? O è più leggibile lasciarlo direttamente in un'unica pagina?
    Parlo del nodo visualizzato, non in fase di edit (in questo caso userò Vertical Tabs per rendere il tutto più ordinato)
  2. Come rendere più elegante il codice qui sotto

Praticamente, nel mio node-menu.tpl.php ho inserito questo:

<?php if (strlen($node->field_categoria2[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria2[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria2 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>

Come già spiegato, io creerò un tot di categorie con sotto i compound per i piatti relativi. Mettiamo che siano 10 categorie massime. In node-menu.tpl.php dovrò inserire quindi 9 volte (10-1) questo:
<?php if (strlen($node->field_categoria2[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria2[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria2 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>
<?php if (strlen($node->field_categoria3[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $node->field_categoria3[0]['view'] ?></tr></td>
<?php foreach($node->field_piatti_categoria3 as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>
stessa cosa per field_categoria4, field_categoria5, ecc.

Invece di scriverlo una decina di volte, devo cercare di fare un ciclo. Ma non essendo un genio del php, ho bisogno di tempo (e suggerimenti!).

Puoi usare le variabili per definire in un ciclo il nome del campo. Tento una soluzione, ma tu consulta la doc. PHP per essere sicuro…

<?php for ($i = 0; $i < 10; $i++) { ?>
   <?php $nome_campo_cat = 'field_categoria'. $i; $nfc = $node->$nome_campo_cat; ?>
   <?php if (strlen($nfc[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $nfc[0]['view'] ?></tr></td>
<?php foreach($nfc as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>
<?php };?>

Grazie mille Pinolo!
Ho modificato un po' il tuo codice e finalmente ce l'ho fatta!
Nel mio esempio ci sono 7 categorie totali. Ho dovuto modificare un po' il codice perché gli "items" dei piatti appartengono ad un'altra field, cioè field_piatti_categorian.
Quindi:

<?php for ($i = 1; $i < 8; $i++) { ?>
   <?php $nome_campo_cat = 'field_categoria'. $i; $nfc = $node->$nome_campo_cat; ?>
   <?php $nome_campo_piat = 'field_piatti_categoria'. $i; $npc = $node->$nome_campo_piat; ?>
   <?php if (strlen($nfc[0]['view']) > 0) { ?>
        <table class="tabella-menu">
    <tr><td class="cel-categoria-piatto"><?php print $nfc[0]['view'] ?></tr></td>
<?php foreach($npc as $key => $fields) : ?>
<?php print $fields['view'] ?>
<?php endforeach ?>
</table>
    <?php };?>
<?php };?>

Adesso è perfetto. Una settimana di tribolazioni ma ne è valsa la pena!
Posso dichiarare definitivamente risolta la discussione!

Dimenticavo: grazie anche a tutti gli altri!