Con l’oggetto “import” è possibile importare in un ds un file di testo effettuando un controllo preventivo sui valori contenuti nel file stesso. In questo modo abbiamo la possibilità di selezionare solo i record che soddisfano le condizioni richieste.
Nel mio caso avevo la necessità di importare dei file di testo nei quali la prima riga conteneva le descrizioni dei campi e l’ultima era vuota.
Grazie alla modifica che Giampiero ha apportato all’oggetto import ho potuto utilizzare il nuovo metodo “data_import_before” per effettuare un ciclo sui valori del ds di origine ($dsFrom). Per ogni record ho verificato che il primo campo fosse numerico. Nel caso non lo fosse ho rimosso il record dall’array tramite il comando “unset“.
Con il nuovo metodo sarebbe inoltre possibile modificare i valori dei campi prima di importarli.
Nell’esempio che segue viene aggiunta la stringa “+++” al campo “rag_soc” e vengono eliminati i record nei quali il campo “id_azienda” non è numerico.
function data_import_before($dsFrom)
{
global $xml;
global $event;
$i=0;
while($row = $dsFrom->ds->dsGetRow())
{
if (is_numeric($row["id_azienda"]))
{
$dsFrom->ds->property["result"][$i]['rag_soc'] = $row["rag_soc"].”+++”;
}
else
{
unset($dsFrom->ds->property["result"][$i]);
}
$i++;
}
}
Ciao a tutti,
qualche giorno fa ci è stato chiesto se era possibile tramite JAMP disegnare un diagramma di Gantt in base a dei dati contenuti in una tabella MYSQL. La risposta è si, grazie infatti all’integrazione di JAMP con le librerie JPGRAPH(già contenute nel framework) è possibile includere diverse tipologie di grafici tra cui i diagrammi di Gantt.
In generale un grafico si realizza collegando uno o più datasources all’oggetto graph senza aggiungere nessuna riga di codice PHP. I diagrammi di Gantt invece necessitano di una logica più accurata e quindi non completamente automatizzabile ma realizzabile comunque facilmente con poche righe di codice in PHP.
Ho risposto preparando un piccolo esempio nel quale i dati inerenti al diagramma saranno visibili all’interno di una gridds e si potranno modificare con la conseguente rigenerazione del grafico il tutto senza ricaricare la pagina perché avverrà tramite transazione AJAX.
Requisti:
La tabella SQL da i mportare:
CREATE TABLE `gantt` (
`key` int(11) NOT NULL auto_increment,
`type` varchar(30) NOT NULL,
`label` varchar(30) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
PRIMARY KEY (`key`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `gantt` (`key`,`type`,`label`,`begin`,`end`) VALUES
('1','ACTYPE_GROUP','Phase 1','2010-10-26','2010-11-23'),
('2','ACTYPE_NORMAL','Label 2','2010-10-26','2010-11-16'),
('3','ACTYPE_NORMAL','Label 3','2010-11-11','2010-11-22'),
('4','ACTYPE_MILESTONE','Phase 1 Done','2010-11-18','2010-11-18');
il sorgente XML con la struttura della pagina:
<?xml version="1.0" encoding="utf-8"?> <jamp> <page typeobj="page" title="JAMP - Grafico di Gantt" out="html" icon="../../favicon.ico" loaddata="true"> <ds1 typeobj="ds" conn="conn6" dstable="gantt" dskey="key" /> <div1 typeobj="div"> <graphic1 typeobj="graphic" width="700" height="200"> <parameter> <plot objtype="plot" shadow="true" frame="true" xaxis="true" yaxis="true" /> <title objtype="title" title="gantt" font="FF_FONT1,FS_BOLD" margin="3" header="GANTT_HYEAR | GANTT_HMONTH | GANTT_HDAY | GANTT_HWEEK" /> <scale objtype="scale" weekstyle="WEEKSTYLE_FIRSTDAYWNBR" weekfont="FF_FONT1" /> </parameter> </graphic1> </div1> <div2 typeobj="div" style="margin: 10px"> <dsnav1 typeobj="dsnav" dsobj="ds1" btPage="false" btNav="false" btPrint="false" /> <gridds1 typeobj="gridds" dsobj="ds1" width="700" height="300"> <coloumn> <col objtype="dsselect" itemlabel="Type" dsitem="type" optionvalue="ACTYPE_NORMAL,ACTYPE_MILESTONE,ACTYPE_GROUP" colwidth="150px" /> <col objtype="text" itemlabel="Label" dsitem="label" minlength="1" colwidth="250px" /> <col objtype="text" format="date|EN|yyyy-mm-dd|IT|dd/mm/yyyy" itemlabel="Begin" dsitem="begin" minlength="1" size="5" /> <col objtype="text" format="date|EN|yyyy-mm-dd|IT|dd/mm/yyyy" itemlabel="End" dsitem="end" minlength="1" size="5" /> </coloumn> </gridds1> </div2> </page> </jamp>
ed infine il codice PHP:
require_once("./../../class/system.class.php");
$system = new ClsSystem(true);
$xml = new ClsXML("dynamic_gantt.xml");
$event = new ClsEvent($xml);
$event->managerRequest();
function start_graph($xml_graphics)
{
global $xml;
$graphic = $xml_graphics->getObjById("graphic1");
$ds = $xml->getObjById("ds1");
$ds->ds->dsConnect();
$ds->ds->dsQuery("SELECT * FROM `gantt`");
$objtype = array(0=>"plot",1=>"title",2=>"scale");
$i=3;
while ($row = $ds->ds->dsGetRow())
{
$objtype[$i] = "gantt";
$type[$i] = $row->type;
$label[$i] = $row->label;
$begin[$i] = $row->begin;
$end[$i] = $row->end;
$i++;
}
$graphic->setProperty("objtype", $objtype);
$graphic->setProperty("type", $type);
$graphic->setProperty("label", $label);
$graphic->setProperty("start", $begin);
$graphic->setProperty("end", $end);
}
Ciao,
Giampiero
Ciao Ragazzi,
vi spiego brevemente il problema: tipico inserimento diretto in griglia con alcuni campi; immaginiamo una tabella tipo:
create table movimenti
{
id int(11) NOT NULL auto_increment,
data_reg date,
descrizione longtext,
entrate decimal(11,2),
uscite decimal(11,2)
}
Quando l’utente inserisce:
1. click sul dsnav “Aggiungi”
2. la griglia crea una nuova riga
ed iniziamo l’inserimento. E se io volessi pre-compilare la data in modo che l’utente non deve ridigitarla ogni volta come faccio ?
Ecco il codice:
function html_load()
{
global $event, $xml;
$code = "
function custom_fnz(dsObjName)
{
var d = new Date();
// si suppone che sia la prima colonna
$('gridds1_1_-1').value = d.getDate()+'/'+d.getMonth()+'/'+d.getFullYear();
TEXT.setDsValue($('gridds1_1_-1'));
}
SYSTEMEVENT.addAfterCustomFunction('DS', 'dsnew', 'custom_fnz');
";
$event->setCodeJs($code);
}
Ecco qua l’esempio; potete copiarlo e provarlo sui vostri progetti.
Grazie a Giampiero per il codice.
Ciao Marco e Samuele.
Ciao Ragazzi, volevo fare questo post per dirvi che non siamo scomparsi,ma in questi ultimi tempi, via per lavoro, via per un’influenza (causa clima
) non abbiamo avuto più modo di fare articoli; ma abbiamo seguito il forum ed abbiamo in programma di fare qualche altro articolo. Ribadiamo che stiamo alla ricerca di “volontari” per scrivere articoli sul funzionamento pratico di JAMP.
A proposito!!!??..RUBEN e GIAMPIERO come va avanti lo sviluppo ? Ci potete in anteprima dare qualche notizia ?
Grazie Marco e Samuele.
Ciao Ragazzi,
eccomi qua con un nuovo articolo; questa volta ho affrontato un altro problema; quello della stampa. Premessa: di solito utilizzo il motore di stampa di JAMP; ma questa volta avevo bisogno di scrivermi una stampa particolare quindi per mia scelta personale ho optato per tcpdf la libreria GPL che trovate su http://www.tcpdf.org dove vi rimando per maggiori dettagli. RIPETO E’ UN MIA SCELTA PERSONALE; quindi mi limito a mostrare degli esempi su come può essere integrata con JAMP.
1° PASSO: Richiamiamo la pagina print_listaordini.php tramite la funzione window.open
function StampaOrdine()
{
alert('Procedura di stampa personalizzata');
var style = 'width=220,height=220,left=0,top=0,resizable=yes,menubar=yes,toolbar=yes,scrollbars=yes,locations=no,status=no';
window.open('print_listaordini.php', '', style);
}
2° PASSO: codice della pagina print_listordini.xml; praticamente semplicissima senza particolari opzioni; tanto poi verrà sostituita con l’oggetto PDF in output.
3° PASSO: Ecco il vero sistema tcpdf; nell’esempio la libreria è stata scaricata ed inserita nella cartella lib dell’applicazione.
E’ DERIVATO DA UNA NOSTRA APPLICAZIONE PER CUI E’ SOLO A SCOPO DI ESEMPIO DOVRETE ADATTARE IL CODICE ALLE VOSTRE ESIGENZE. GRAZIE.
require_once("./../../class/system.class.php");
$system = new ClsSystem(true);
$xml = new ClsXML("print_listaordini.xml");
$event = new ClsEvent($xml);
$event->managerRequest();
function html_before_load()
{
global $system;
$ds = $system->newObj("ds", "ds");
$ds->setProperty("conn", "jordini");
$ds->ds->dsConnect();
$ds->ds->dsQuerySelect("SELECT * FROM `ordini_testa`");
// NUOVO SISTEMA DI STAMPA
require_once('lib/tcpdf/config/lang/ita.php');
require_once('lib/tcpdf/tcpdf.php');
class MYPDF extends TCPDF {
//Page header
public function Header() {
// Logo
//$this->Image(K_PATH_IMAGES.'logo_example.jpg', 10, 8, 15);
// Set font
$this->SetFont('helvetica', 'B', 20);
// Move to the right
$this->Cell(80);
// Title
$this->Cell(30, 10, 'JORDINI - VERSIONE BETA - LISTA ORDINI', 0, 0, 'C');
// Line break
$this->Ln(20);
}
// Page footer
public function Footer() {
// Position at 1.5 cm from bottom
$this->SetY(-15);
// Set font
$this->SetFont('helvetica', 'I', 8);
// Page number
$this->Cell(0, 10, 'Elaborato da Marco e Samuele - Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, 0, 'C');
}
}
$pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->setLanguageArray($l);
$pdf->SetFont('times', 'BI', 12);
$pdf->AddPage();
$pdf->SetFillColor(255, 0, 0);
$pdf->SetTextColor(255);
$pdf->SetDrawColor(128, 0, 0);
$pdf->SetLineWidth(0.3);
$pdf->SetFont('', 'B');
$w = array(20, 30, 40, 45, 45, 45);
$pdf->cell($w[0], 7, 'N.Ordine', 1, 0, 'C', 1);
$pdf->cell($w[1], 7, 'Data ', 1, 0, 'C', 1);
$pdf->cell($w[2], 7, 'Agente', 1, 0, 'C', 1);
$pdf->cell($w[3], 7, 'Fornitore', 1, 0, 'C', 1);
$pdf->cell($w[4], 7, 'Cliente', 1, 0, 'C', 1);
$pdf->cell($w[5], 7, 'Totale', 1, 0, 'C', 1);
$pdf->Ln();
$pdf->SetFillColor(224, 235, 255);
$pdf->SetTextColor(0);
$pdf->SetFont('');
$i=0;
$fill = 0; // COLORI ALTERNATI
while($row = $ds->ds->dsGetRow())
{
$pdf->Cell($w[0], 6, $row->ord_numero, 'LR', 0, 'L', $fill);
$pdf->Cell($w[1], 6, $row->ord_dataordine, 'LR', 0, 'L', $fill);
$pdf->Cell($w[2], 6, valoredb('agenti', 'age_codice', 'id', $row->ord_agente), 'LR', 0, 'L', $fill);
$pdf->Cell($w[3], 6, valoredb('fornitori', 'for_ragionesociale', 'id', $row->ord_fornitore), 'LR', 0, 'L', $fill);
$pdf->Cell($w[4], 6, $row->cli_ragionesociale, 'LR', 0, 'L', $fill);
$pdf->Cell($w[5], 6, number_format($row->ord_netto), 'LR', 0, 'R', $fill);
$pdf->Ln();
$fill=!$fill;
$i++;
}
$pdf->Cell(array_sum($w), 0, '', 'T');
$pdf->Output('lista_ordini.pdf', 'I');
}
function valoredb($tabella, $campo, $ricerca, $valore)
{
global $system;
$ds = $system->newObj("ds", "ds");
$ds->setProperty("conn", "jordini");
$ds->ds->dsConnect();
$ds->ds->dsQuerySelect("SELECT " . $campo . " FROM `" . $tabella . "` WHERE " . $ricerca . " = '" . $valore . "'");
$row = $ds->ds->dsGetRow();
return $row->$campo;
}
Aspetto i vostri commenti in merito; ve avete delle curiosità o quant’altro non esitate a scrivermi.
Grazie per l’attenzione. Ciao Marco e Samuele.
Ciao Ragazzi,
in questi giorni stavo affrontando un problema che all’apparenza sembrava semplice;ma non avevo ancora ben presente come effettuare un’operazione semplice; cioè applicare e/o modificare i filtri che impostiamo a priori dal codice applicato al DSNAV nel file xml;
Con il codice sarà molto più semplice spiegare questa cosa:
Guardate il seguente codice:
Bene, ricerco il mio cliente associato al ds1 e filtro per ragionesociale e ragionesociale1; si noti che la variabile $$VALUE$$ sarà il risultato del text di ricerca dopo che JAMP avrà elaborato la nostra richiesta.
PROBLEMA: SE OLTRE ALLA RAGIONESOCIALE DEVO PER ESEMPIO RICERCARE IN BASE ALLA PROVINCIA DELL’UTENTE LOGGATO SULL’APPLICAZIONE COME POSSO FARE ?
(chiaramente non posso applicare tale filtro sulla pagina xml perchè non so a priori l’utente di quale regione si collegherà al mio applicativo)
RISOLUZIONE 1:
function html_load()
{
global $event;
$code = "
function filtra_cli(dsObjName)
{
var obj = $(dsObjName);
var val = obj.p.DSsearch.replaceAll('\$\$VALUE\$\$', $(dsObjName + '_search').value.replace(/'/g,'\\''));
var dsObj = $(obj.p.dsObj);
dsObj.DSsearch = val+' AND clienti_provincia = \'".$_SESSION['provincia']."\'';
AJAX.dsmore(dsObj, 'data=load&dsobjname=' + dsObj.id);
return false;
}
SYSTEMEVENT.addBeforeCustomFunction('DSNAV','dsfind', 'filtra_cli');
";
$event->setCodeJs($code);
}
Si da per scontato che la variabile $_SESSION["provincia"] riporti la provincia da filtrarte ad esempio “MI” per milano. Definisco l’evento AJAX che il DSNAV in fase di ricerca mi permette di intercettare
SYSTEMEVENT.addBeforeCustomFunction(‘DSNAV’,'dsfind’, ‘filtra_cli’);
e mi creo la mia funzione filtra_cli sempre in JS.
Cito il commento di Giampiero:
le modifiche effettuate al metodo dsfind sono 2:
- aggiunta del codice necessario per il filtro: dsObj.DSsearch = val+’ AND clienti_provincia = \’”.$_SESSION['provincia'].”\”;
- return false; al termite della funzione “filtra_cli” serve ad evitare che venga richiamato l’evento dsfind il quale effettuerebbe una nuova richiesta AJAX.
RISOLUZIONE 2:
function html_load()
{
global $event;
$code = "
function filtra_cli(dsObjName)
{
var obj = $(dsObjName);
dsObj.DSsearch = '(`cli_ragionesociale` LIKE \'%\$\$VALUE\$\$\%\' or `cli_ragionesociale1` LIKE \'%\$\$VALUE\$\$%\') AND clienti_provincia = \'".$_SESSION['provincia']."\'';
}
SYSTEMEVENT.addBeforeCustomFunction('DSNAV','dsfind', 'filtra_cli');
";
$event->setCodeJs($code);
}
Come vedeta la differenza sta nel modificare solo l’attributo DSsearch del mio oggetto DS e lasciamo a JAMP l’esecuzione del metodo di ricerca.
!!!!ATTENZIONE!!!!
Per evitare problematiche legate al quoting si può adottare un’altra soluzione utile soprattutto quando il codice javascript è parecchio, consiste nell’inserire il codice in un file esterno e poi includerlo all’interno della pagina PHP come segue:
function html_load()
{
global $event;
$code = file_get_contents('filename.js');
$event->setCodeJs($code);
}
Concludo con la speranza di avervi possato qualcosa di utile; chiaramente ribadisco che se non sono stato chiaro vi prego di lasciare commenti, cercherò di rispondervi.
Grazie per l’attenzione. Marco e Samuele. Aesis.
Grazie a Giampiero per la pazienza avuta nel spiegarmi il tutto.
Ps. Se ho commesso qualche errore non fateci caso..in fondo sono un programmatore.
Spesso è utile o necessario eseguire in automatico determinate operazioni (es. reload di oggetti, svuotare oggetti text, etc…) nel momento in cui si passa da un tab ad un altro.
Con JAMP questa operazione è semplicissima. E’ sufficiente intercettare l’evento setFocus della classe TABS ed associargli una funzione. A questa funzione vengono passati l’ID dell’oggetto TABS e l’ID del TAB appena selezionato.
In questo modo con dei semplici if possiamo intraprendere le azioni necessarie, come nell’esempio qui sotto.
L’unica accortezza che dobbiamo avere nel gestire questi eventi riguarda il TAB di default, ossia quel TAB selezionato in automatico al caricamento della pagina (nell’esempio qui sotto è “tab1″). Questo perché l’evento setFocus viene scatenato anche inizalmente, al momento del caricamento della pagina, quando non tutti gli oggetti sono stati instanziati.
Pertanto è sufficiente verificare che l’oggetto a cui vogliamo “mettere mano” sia istanziato prima di richiamarne alcuna funzione. Nell’esempio qui sotto, per verificare che ds1 fosse già istanziato è stato sufficiente verificare che l’attributo DSpos fosse stato definito.
function onTabChange(id, box)
{
// TAB 1 di DEFAULT
if (box == 'tab1') {
if ($('ds1').DSpos != undefined) {
ds1Refresh();
}
// TAB 2
} else if (box == 'tab2') {
ds2Refresh();
// TAB 3
} else if (box == 'tab3') {
ds3Refresh();
}
}
SYSTEMEVENT.addBeforeCustomFunction('TABS','setFocus', 'onTabChange');
Paolo (Plrunner)
Questo semplice tips permette di attivare il DS in inserimento; molto utile se volete gestire le varie funzioni del DS manualmente, un alternativa al dsnav.
Chiaramente questo avviene in fase di caricamento della pagina.
function html_load()
{
global $xml;
$xml->pageObj->addEvent("page", "ds1Refresh", "if ($('ds1').autoinsert != true){ DS.dsnew('ds1'); $('ds1').autoinsert = true; }");
}
NOTE: Va fatto nell’evento Refresh perchè diamo la possibilità al framework di finire il caricamento dei dati e dei vari oggetti.
Prendendo spunto dal Forum (Luposoft); per conoscere il tab selezionato possiamo utulizzare il seguente codice:
$code = "
function tabSelezionato(id,box)
{
alert(box); //Compare un messaggio di dialogo che indica il TAB (box) selezionato
}
SYSTEMEVENT.addBeforeCustomFunction('TABS','setFocus','tabSelezionato');
";
$event->setCodeJs($code);
Prendendo spunto dal Forum (plrunner); è utilissimo controllare il valore di un combo che abbiamo in una maschera. Questa procedura va fatta in JS lato client.
Incollate sulle vostre procedure:
function controlla {
var combo = $('dscombo1');
if ((combo.valuekey == undefined) || (combo.valuekey == '')) {
alert('Attenzione: non hai selezionato il valore dall\'elenco.');
return false; // INTERROMPE LA PROCEDURA
}